1

I have a MongoDB document something like this:

    "_id" : ObjectId("5ccb4067d0c24b35d4cbb51e"),
    "title" : "Sharing test 1",
    "content": "Test Content",
    "creator" : ObjectId("5c715d627adcfb7980c5d4c2"),
    "createdAt" : ISODate("2019-05-03T00:39:27.594+05:30"),
    "lastUpdatedAt" : ISODate("2019-05-03T00:39:27.609+05:30"),
    "sharingInfo" : [ 
        {
            "_id" : ObjectId("5c715d627adcfb7980c5d6c2"),
            "accessType" : "edit"
        }, 
        {
            "_id" : ObjectId("5c72acf12f63693410f2ae1a"),
            "accessType" : "view"
        }
    ]

In the field sharingInfo i want to insert a document in a behaviour mentioned below:

If the _id fields with same value already exists then update the value of accessType otherwise create a fresh new entry.

I will try to explain with two examples.

Example 1

Let's suppose i am trying to insert a document like this:

  {
    "_id" : ObjectId("5c72acf12f63693410f2ae1a"),
    "accessType" : "edit"
  }

As this _id already exists, the resultant sharingInfo should like:

    "sharingInfo" : [ 
        {
            "_id" : ObjectId("5c715d627adcfb7980c5d6c2"),
            "accessType" : "edit"
        }, 
        {
            "_id" : ObjectId("5c72acf12f63693410f2ae1a"),
            "accessType" : "edit"
        }
    ]

Example 2

Let's suppose i am trying to insert a document like this:

  {
    "_id" : ObjectId("5ccb4070d0c24b35d4cbb520"),
    "accessType" : "view"
  }

As this _id doesn't already exists, the resultant sharingInfo should like:

    "sharingInfo" : [ 
        {
            "_id" : ObjectId("5c715d627adcfb7980c5d6c2"),
            "accessType" : "edit"
        }, 
        {
            "_id" : ObjectId("5c72acf12f63693410f2ae1a"),
            "accessType" : "edit"
        },
        {
            "_id" : ObjectId("5ccb4070d0c24b35d4cbb520"),
            "accessType" : "view"
        }
    ]

I came across the operator $addToSet but it compares the entire document, i can't make it compare based on a particular field _id

If i can drop duplicates based on certain conditions that will also work, but i found dropDups is no longer available with recent versions of MongoDB.

When i want to update sharingInfo with some data, i receive the data in an array of Object format: For example:

[
  {
    "_id" : ObjectId("7d72acf12f63693410f2ae1b"),
    "accessType" : "edit"
  },
  {
    "_id" : ObjectId("8acb4070d0c24b35d4cbb521"),
    "accessType" : "view"
  }
]

If i try to perform a $set operation the entire content of sharingInfo gets replaced with the new data.

The idea here is to minimise number of API request, if someone wants to update the sharing info with multiple data, he/she can send a single API request with an Array of objects to be updated as payload.

I am using mongoose to model my data.

Is there any efficient way to achieve the entire operation ?

I can perform multiple read write operation in the DB but that will be highly inefficient, don't want that.

This is something update if exists otherwise insert in an array of documents

PS: I am new to MongoDB.

Thanks in advance.

  • 1
    What you are after actually requires **two** update operations, probably best handled with `bulkWrite()`. One will attempt to `$set` the matched element where the `_id` was found, and the other will `$push` where it does not exist, Also note that `dropDups` was an old thing for "unique indexes", and those do not apply to arrays here since "unique" means **across the collection** and not **within the array**. Array "uniqueness" is enforced by code, and not by indexes. – Neil Lunn May 04 '19 at 00:22
  • @NeilLunn How can i filter a sub document ? I tried running something like this: ```javascript await lContent.find({ _id: req.params.Id, 'sharingInfo._id': { $in: ids }, }); ``` But this returns the entire sub document – Shirshendu Bhowmick May 04 '19 at 10:23
  • If you have a new question then [Ask a new question](https://stackoverflow.com/questions/ask). But beware that [Retrieve only the queried element in an object array in MongoDB collection](https://stackoverflow.com/q/3985214/2313887) along with many other "starting to use MongoDB" questions, have already been answered some time ago. Look for answers before posting. If you think an existing answer does not solve your problem, then show exactly why it does not work. Also please don't attempt to post code in comments. That's what questions are for instead. – Neil Lunn May 04 '19 at 10:26
  • @NeilLunn I have updated the question and tried to explain how its a bit different from other threads. – Shirshendu Bhowmick May 04 '19 at 10:37
  • I see no difference. If it were different then you would be showing implemented code which does the same thing as existing answers but still does not get the desired result. There is none of that in your question. I suggest actually reading the answers you've been pointed to and implementing the code just like they show you to do. – Neil Lunn May 04 '19 at 12:49

2 Answers2

0

Typically you would use mongoose to find the document you want to update, update its sharingInfo array appropriately and then save the document. I am not aware of anyway to do what is described in an atomic operation.

ekill
  • 176
  • 7
0

instead of adding whole object to sharingInfo Array ...

save it in diffrent collection and push it's _id in sharingInfo with help of $addToSet..

now if it is view or edit you just go and update that particulate data with _id .. refrence can be populated with help of .populate(fieldName)... refer mongoose docs for more..

Visit : Mongoose - Populate

Excalibur
  • 367
  • 1
  • 7