1

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!

0

2 Answers 2

1

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

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

4 Comments

hey! thanks for time, however this dosn't solve the issue because if you assume there is already a movieId called test in the array, this quary will add another item to the array with the same movie id, which is what I want to avoid.
udjusted the answer accordingly ...
Here the original and some more ideas : stackoverflow.com/questions/69747575/…
wow this looks really comlex, i didn't think it will be this hard!
0

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}`]:""}})

Comments

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.