Home > OS >  Push to a nested array or push to array based on the item id - MongoDb node.js
Push to a nested array or push to array based on the item id - MongoDb node.js

Time:01-17

I have this schema:

...
recommended:{
    type:[{
        movieId:String,
        recommendedBy:[String]
    }],
    default:[],
},
name: {
    type: String,
}

from the request I get movieId and id. I want to add to recommended array a new object if there is no other item with the same movieId there already, and add theid to the recommendedBy nested array in both cases.

so far I have this:

        const user = User.findByIdAndUpdate({_id:'123'},
            {$AddToSet:{'recommended.$[movie].recommendedBy':id}},
            {arrayFilters:[{'movie.movieId':movieId}]})

this will only set the recommendedBy of an already existing item with the same movieId, but will not push a new object with the new movieId property. (so it's basically $AddToSet for both arrays) How could I achieve that? thanks!

CodePudding user response:

Maybe you need something simple like this that is doing upsert or update for the recommended array element:

 db.collection.update({},
  [
   {
    $set: {
     recommended: {
      "$reduce": {
        "input": "$recommended",
        "initialValue": // assign your edit data as init value
        [
        {
          "movieId": "1",
          "recommendedBy": "who recommended"
        }
      ],
      "in": {
        "$cond": {
          "if": {
            $in: [
              "$$this.movieId",
              "$$value.movieId"
            ]
          },
          "then": "$$value",
          "else": {
            "$concatArrays": [
              "$$value",
              [
                "$$this"
              ]
            ]
             }
             }
             }
            }
          }
        }
      }
    ])

explained:

  1. No filter but you can add anything in the initial document filter to search only limited set of documents.
  2. In the update stage you use $reduce to check input array elements that you need to upsert or update the value in the affected array element.

( Confirmed to work in mongod 4.4 )

playground

CodePudding user response:

I couldn't understand @R2D2's answer so I came up with this workaround which does unexpectedly well for me, since I also need to be able to remove the movieId and all the recommendedBy with it.

I changed my schema to this:

    recommanded:{
      type: Map,
      of:[String],
      default:{}
    },

I'm removing/ adding with:

User.findByIdAndUpdate({_id:"123",{$addToSet:{[`recommended.${movieId}`]:id}})

And

User.findByIdAndUpdate({_id:"123",{$unset:{[`recommended.${movieId}`]:""}})
  •  Tags:  
  • Related