Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to toggle an element in array in mongoDB

Tags:

mongodb

I have an array of string (ObjectIds) in mongoDB. I want to toggle an element in that array: If that element exists in the array, remove it, otherwise push that element.

Example:

arr = ["5b608c0769698c3990c64ef3","5b608c0769698c3990c64ef4"]
element = ["5b608c0769698c3990c64ef3"]

Final array:

arr = ["5b608c0769698c3990c64ef4"]

My use-case:

I am creating a blog website and in the Blog Schema I am storing the id of each user who has liked that blog, so that I can highlight the like button when blog is shown to the user.

like image 425
dasfdsa Avatar asked Jul 31 '18 16:07

dasfdsa


2 Answers

If you are updating the document, you can use the pipeline within the update. But this feature is available with MongoDB version 4.2 or later.

db.collection.update(
  { },
  [
     { 
          $set: { 
              arr: { 
                  $cond: [ { $in: [ element, "$arr" ] }, 
                           { $setDifference: [ "$arr", [ element ] ] }, 
                           { $concatArrays: [ "$arr", [ element ] ] } 
                  ] 
              }
          }
     }
  ]
)

NOTE: Assuming the variable element is a string value.

If you are just querying you can use the following aggregation:

db.collection.aggregate([
     { 
          $addFields: { 
              arr: { 
                  $cond: [ { $in: [ element, "$arr" ] }, 
                           { $setDifference: [ "$arr", [ element ] ] }, 
                           { $concatArrays: [ "$arr", [ element ] ] } 
                  ] 
              }
          }
     }
] )

But, if you are using MongoDB version earlier than 4.2, then you can use the aggregate output from above to update the document:

db.collection.aggregate( [
  // aggregation pipeine from above ...
] ).forEach( doc => db.collection.updateOne( { _id: doc._id }, { $set: { arr: doc.arr } } ) )
like image 77
prasad_ Avatar answered Sep 29 '22 01:09

prasad_


Its maybe not the best solution, but a easy one. You can add your element to the array with $addToSet and check with nModified if you modified the array. 0 means it already exist, and 1 mean you added new Element to it.

So you use mongoose as you said then you have a Model lets say Post. I dont know witch backend langauge you use, but i will show it with node.js here:

let result = await Post.updateOne({ _id: "someId" }, { 
   $addToSet: {
      arr: element
   }
})

if(result.nModified === 0){
   //0 means, no modifikation, that means its already liked
   await Post.updateOne({ _id: "someId" }, {
      $pull: {
         arr: element
      }
   })
}
response.send("Done");
like image 21
Ifaruki Avatar answered Sep 29 '22 03:09

Ifaruki