Core Server
  1. Core Server
  2. SERVER-3326

Support $ positional operator with an upsert

    Details

    • Backport:
      No
    • # Replies:
      0
    • Last comment by Customer:
      true

      Description

      According to the documentation, this limitation currently applies to upserts:
      <quote>
      The positional operator cannot be combined with an upsert since it requires
      a matching array element. If your update results in an insert then the "$"
      will literally be used as the field name.
      </quote>

      When performing a findAndModify it would be incredibly powerful to support the insert condition for a document that does not exist. It would save on multiple calls to the Mongo Server and allow for a single atomic update/insert for a document with embedded arrays.

      Below is JavaScript that can be run in the Mongo Shell to demonstrate this powerful capability:

      The purpose of these documents is keep track of the last login per user per type of login. And to create the user document if it does not already exist in a single atomic transaction.

      db.user_identities.ensureIndex({"user" : 1}, {unique : true});
      db.user_identities.save({
          user: 'user1',
          first_seen: 'date1',
          last_seen: [
              { type: 'TA', date: 'date1' }
          ]
      })
      
      db.user_identities.save({
          user: 'user2',
          first_seen: 'date2',
          last_seen: [
              { type: 'TA', date: 'date2' },
              { type: 'PP', date: 'date3' }
          ]
      })
      
      db.user_identities.save({
          user: 'user3',
          first_seen: 'date3',
          last_seen: [
              { type: 'TA', date: 'date3' },
              { type: 'PP', date: 'date4' }
          ]
      })
      
      // Existing entry - Works as expected
      db.user_identities.findAndModify({
          query: {"user":"user3", "last_seen" : {$elemMatch : {"type": "PP", "date" : { $lte: "date4"} }}},
          update: {$set: {"last_seen.$":{ type: 'PP', date: 'date5' }}},
          upsert: true,
          "new": true}) 
      
      /* Returns the following:
      {
              "_id" : ObjectId("4e034dd979ee2fd2e506ce24"),
              "user" : "user3",
              "first_seen" : "date3",
              "last_seen" : [
                      {
                              "type" : "TA",
                              "date" : "date3"
                      },
                      {
                              "type" : "PP",
                              "date" : "date5"
                      }
              ]
      } 
      */
      
      // Non-existent - Inserts the $ as the element name in the new
      document
      db.user_identities.findAndModify({
          query: {"user":"user4", "last_seen" : {$elemMatch : {"type": "PP", "date" : { $lte: "date6"} }}},
          update: {$set: {"last_seen.$":{ type: 'PP', date: 'date6' }}},
          upsert: true,
          "new": true}) 
      
      /* Returns:
      {
              "_id" : ObjectId("4e034dd9f0e57cca9b6f045a"),
              "last_seen" : {
                      "$" : {
                              "type" : "PP",
                              "date" : "date6"
                      }
              },
              "user" : "user4"
      
      }
      */
      

        Issue Links

          Activity

          • Comments
          There are no comments yet on this issue.

            People

            • Assignee:
              Unassigned
              Reporter:
              Reid Morrison
              Participants:
              Last commenter:
              Ian Whalen
            • Votes:
              28 Vote for this issue
              Watchers:
              21 Start watching this issue

              Dates

              • Created:
                Updated:
                Days since reply:
                2 years, 43 weeks, 5 days ago