0

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)

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! For some reason I don't need the subtract function because size([{},{}]) is 1. Can you explain why is that?
I don't think an array with 2 objects will give you size/length as 1.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.