Announcement Announcement Module
Collapse
No announcement yet.
Support of MongoDB update $pull operation with expressions Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Support of MongoDB update $pull operation with expressions

    Hi all,
    I was wondering if the Update pull method supports expressions of the type
    Code:
    { $pull : { field : {field2: value} } } removes array elements with field2 matching value
    Code:
    { $pull : { field : {$gt: 3} } } removes array elements greater than 3
    Code:
    { $pull : { field : {<match-criteria>} } } removes array elements meeting match criteria
    In particular my case is as follows:

    Code:
    public void removeByOfficeAndLastUpdatedDate(Long officeOid, Collection<Long> departureOids, Date olderThan) {
    
            Update cabinFareUpd = new Update();
    
            WriteResult updateResult = this.mongoTemplate.updateMulti(
                query(where(BaseFareFields.OFFICE_OID.getValue()).is(officeOid).
                    and(BaseFareFields.DEPARTURE_OID.getValue()).in(departureOids).
                    and(BaseFareFields.CABIN_FARE.getValue()).elemMatch(where(BaseFareFields.LAST_UPDATED_DATE.getValue()).lte(olderThan))),
                cabinFareUpd.pull(BaseFareFields.LAST_UPDATED_DATE.getValue(),
                    query(where(BaseFareFields.LAST_UPDATED_DATE.getValue()).lte(olderThan))), BaseFare.class);
    
            logger.info(updateResult.toString());
    
        }
    Basically I want to remove an array element within a document whose last udpated date is less that the informed date.

    The execution of the pull method as written above currently throws an exception:
    Code:
    java.lang.StackOverflowError
    	at java.util.HashMap$EntryIterator.<init>(Unknown Source)
    	at java.util.HashMap$EntryIterator.<init>(Unknown Source)
    	at java.util.HashMap.newEntryIterator(Unknown Source)
    	at java.util.HashMap$EntrySet.iterator(Unknown Source)
    	at java.util.AbstractMap.hashCode(Unknown Source)
    	at org.springframework.util.ObjectUtils.nullSafeHashCode(ObjectUtils.java:336)
    	at org.springframework.data.util.TypeDiscoverer.hashCode(TypeDiscoverer.java:365)
    	at org.springframework.data.util.ClassTypeInformation.hashCode(ClassTypeInformation.java:39)
    	at java.util.concurrent.ConcurrentHashMap.hash(Unknown Source)
    	at java.util.concurrent.ConcurrentHashMap.get(Unknown Source)
    	at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:151)
    ...
    I have attached the complete stack trace here Attachment
    Thanks in advance for your help,

    Sebastian
    Attached Files

  • #2
    I have refined the example a bit based on some additional research:
    1) The elemMatch part has been removed per this note on MongoDB's explanation of the use of $pull with expressions: "Because of this feature, to use the embedded doc as a match criteria, you cannot do exact matches on array elements."
    2) The key has been replaced to BaseFareFields.CABIN_FARE.getValue() as this is the array element in the document.
    Thus here's the updated code:
    Code:
    public void removeByOfficeAndLastUpdatedDate(Long officeOid, Collection<Long> departureOids, Date olderThan) {
    
            Update cabinFareUpd = new Update();
    
            WriteResult updateResult = this.mongoTemplate.updateMulti(
                query(where(BaseFareFields.OFFICE_OID.getValue()).is(officeOid).and(BaseFareFields.DEPARTURE_OID.getValue())
                    .in(departureOids)), 
                cabinFareUpd.pull(BaseFareFields.CABIN_FARE.getValue(),
                    query(where(BaseFareFields.LAST_UPDATED_DATE.getValue()).lte(olderThan))), 
                BaseFare.class);
    
            logger.info(updateResult.toString());
    
        }
    Either if I pass the object as query or criteria (just where(...)) I still get the same StackOverflow error...

    What I am trying to reflect in the code is the following:

    Code:
    db.baseFare.update({ "officeOid" : 1 , "departureOid" : { "$in" : [ 70000]}}, { $pull : {cabinFare: { lastUpdatedDate: { $lte: new Date(2012, 8, 20) } } } }) => Using new Date just in javascript
    Which I have tested and accomplishes what is expected i.e. removing a cabinFare whose lastUpdatedDate is less than or equal to 09/20/2012.

    Comment


    • #3
      I've come up with a solution that includes DBObject objects exposed directly as a way to deal with the nested expressions in the update:

      Code:
          public void removeByOfficeAndLastUpdatedDate(Long officeOid, Collection<Long> departureOids, Date olderThan) {
      
              DBObject lastUpdatedDateUpd = new BasicDBObject(BaseFareFields.LAST_UPDATED_DATE.getValue(), new BasicDBObject(
                  "$lte", olderThan));
      
              Update cabinFareUpd = new Update();
      
              cabinFareUpd.pull(BaseFareFields.CABIN_FARE.getValue(), lastUpdatedDateUpd);
      
              WriteResult updateResult = this.mongoTemplate.updateMulti(
                  query(where(BaseFareFields.OFFICE_OID.getValue()).is(officeOid).and(BaseFareFields.DEPARTURE_OID.getValue())
                      .in(departureOids)), cabinFareUpd,
                  BaseFare.class);
      
              logger.info(updateResult.toString());
      
          }
      Hope that it is useful to someone dealing with similar update requirements.

      Cheers,

      Sebastian

      Comment

      Working...
      X