Netanel
Netanel

Reputation: 519

MongoDB - Increment a field using another array field

I have a collection with the document of this structure:

{
  "_id": {
    "$oid": "63e8af476a3674484ea14888"
  },
  "my_id": 321123,
  "version": 0,
  "parameters": [
    {"a": 1},
    {"a": 1, "b": 2}
  ]
}

Using a RESTful API the user can change the version field to any number between 0 and len(parameters). Another endpoint let the user push an object to parameters and set version to the new len(parameters) - 1. So using the previous example, after using this endpoint we will get:

{
  "_id": {
    "$oid": "63e8af476a3674484ea14888"
  },
  "my_id": 321123,
  "version": 2,
  "parameters": [
    {"a": 1},
    {"a": 1, "b": 2},
    {"a": 1, "b": 2, "c": 3}
  ]
}

I tried many things, but nothing seems to work. Here are examples of what I tried:

db.parameters.findOneAndUpdate({"my_id": 321123}, {"$inc":{version: parameters}, "$push":{"a": 1, "b": 2, "c": 3}}, upsert=true)
db.parameters.findOneAndUpdate({"my_id": 321123}, {"$inc":{version: {"$size": parameters}}, "$push":{"a": 1, "b": 2, "c": 3}}, upsert=true)

Upvotes: 0

Views: 40

Answers (1)

Yong Shun
Yong Shun

Reputation: 51125

As your update requires referring to another field, you have to use the update query with the aggregation pipeline.

For the first scenario,

  1. Add a new parameter object by combining it with the current parameters array via $concatArrays.

  2. I don't think that increment is what you need, but rather update the version value via $set stage. An example as below is to compare the version param between the range of 0 and len(parameters), if true, then update with the version param, else update with the size of the parameters array.

db.parameters.update({
  "my_id": 321123
},
[
  {
    "$set": {
      parameters: {
        "$concatArrays": [
          "$parameters",
          [
            {
              "a": 1,
              "b": 2,
              "c": 3
            }
          ]
        ]
      }
    }
  },
  {
    "$set": {
      version: {
        $cond: {
          if: {
            $and: [
              {
                $gt: [
                  2,
                  // version
                  0
                ]
              },
              {
                $lt: [
                  2,
                  // version
                  {
                    $size: "$parameters"
                  }
                ]
              }
            ]
          },
          then: 2,
          else: {
            $size: "$parameters"
          }
        }
      }
    },
    
  }
],
{
  upsert: true
})

Demo (1st scenario) @ Mongo Playground


For the second scenario,

  1. Add a new parameter object by combining it with the current parameters array via $concatArrays.

  2. Set the version with the size of parameters array minus 1.

db.parameters.update({
  "my_id": 321123
},
[
  {
    "$set": {
      parameters: {
        "$concatArrays": [
          "$parameters",
          [
            {
              "a": 1,
              "b": 2,
              "c": 3
            }
          ]
        ]
      }
    }
  },
  {
    "$set": {
      version: {
        "$subtract": [
          {
            $size: "$parameters"
          },
          1
        ]
      }
    },
    
  }
],
{
  upsert: true
})

Demo (2nd scenario) @ Mongo Playground

Upvotes: 1

Related Questions