Rakesh Jain
Rakesh Jain

Reputation: 235

Update Object Inside the Array of object in a mongoose document with projection or select

I am trying to update the object inside the document

Document: Cats

{
        "_id": "5e5cb512e90bd40017385305",
        "type": "cat"
        "history": [
          {
            "id": "randomID",
            "content": "xyz",
          },
          {
            "id": "randomID2",
            "content": "abc",
          }
        ]
}

Code to select and update the object inside the history array:

const editHistory = async (_, { input }, ctx) => {
  let query = { _id: input.catId, "history.id": input.historyId };
  let update = { $set: { "history.$": input.history } };
  let options = {
    new: true,
    fields: { history: { $elemMatch: { id: "randomID" } } }
  };

  let cat = await ctx.models.cats.findOneAndUpdate(query, update, options);

  return cat;
};

Input has following values

input: {
catId: "5e5cb512e90bd40017385305",
historyId: "randomID",
history: {
id: "randomID",
content: "new content"
}}

I tried using Projection, I used select changed it to field, found in mongoose documentation. I still couldn't update the values. Is there anything wrong with the way i am querying or selecting the subfield.

Upvotes: 0

Views: 173

Answers (1)

Rakesh Jain
Rakesh Jain

Reputation: 235

Found the Solution for it by going through more detail of the operator($set) and option(new, fields).

Question:

const editHistory = async (_, { input }, ctx) => {
  let query = { _id: input.catId, "history.id": input.historyId };
  let update = { $set: { "history.$": input.history } };
  let options = {
    // using new option would return the new document
    new: true, 
    /* using fields option would select the based on the given key, but using new: 
       true with fields will throw error: 'cannot use a positional projection and 
   return the new document'
   */
    fields: { history: { $elemMatch: { id: "randomID" } } } 
  };

  let cat = await ctx.models.cats.findOneAndUpdate(query, update, options);

  return cat;
};

This post below answers that question for *error: 'cannot use a positional projection and return the new document'.

https://stackoverflow.com/a/46064082/5492398

Final Solution:

const editHistory = async (_, { input }, ctx) => {
  let query = { _id: input.catId, "history.id": input.historyId };
  let update = { $set: { "history.$": input.history } };
  let options = {
    new: true
  };

  let cat = await ctx.models.cats.findOneAndUpdate(query, update, options);

  return cat;
};

Removing field option, since I don't need the unmodified selection before atomic modification, solves the question.

Upvotes: 1

Related Questions