10

I have the following schema.

{
   posts: [
          {
             _id: '5ayuunbdsyuuuyut778'
             replies: [{
                 _id: "67hfudj7e9whduu888",
                 text: "something"
             }]
          }
      ]
}

I want to update the text in particular reply. I am using mongoose.

I have written the query as follows

Post.findOneAndUpdate(
   {'posts.replies._id': _id}, 
   {$set: {'posts.$[post].replies.$[reply].text': "something1"}},
   { arrayFilters: [{'post._id': postId}, { 'reply._id': _id }]}
 )

This query is not updating the document.

Am I missing something? Do I need to cast ids using ObjectId

Ashh
  • 44,693
  • 14
  • 105
  • 132
  • Are you getting any error? Because above query works for me... Probably your `postId` or `_id` would not be correct... I have tried this `User.findOneAndUpdate( {'posts.replies._id': "67hfudj7e9whduu888"}, {$set: {'posts.$[post].replies.$[reply].text': "something12"}}, { arrayFilters: [{'post._id': "5ayuunbdsyuuuyut778"}, { 'reply._id': "67hfudj7e9whduu888" }]} )` – Ashh Jul 13 '18 at 12:31
  • which version on mongo are you using? – mehta-rohan Jul 13 '18 at 12:32
  • @Anthony Winslet. I am not getting any error. I am getting the doc without updating when I use {new:true} – Kodanda Rama Durgarao poluri Jul 13 '18 at 15:14
  • are they updating in the database? And how you are using `multi: true`? – Ashh Jul 13 '18 at 15:33
  • I haven't used multi: true. Do I need to? – Kodanda Rama Durgarao poluri Jul 13 '18 at 16:31
  • Sorry I mean `new: true`... How you used it? and put `@` so that I can get the notification – Ashh Jul 13 '18 at 16:46
  • @Anthony Winslet User.findOneAndUpdate( {'posts.replies._id': "67hfudj7e9whduu888"}, {$set: {'posts.$[post].replies.$[reply].text': "something12"}}, { arrayFilters: [{'post._id': "5ayuunbdsyuuuyut778"}, { 'reply._id': "67hfudj7e9whduu888" }]}, {new:true} ) – Kodanda Rama Durgarao poluri Jul 13 '18 at 18:55

3 Answers3

13

You need to use new: true to get the updated value and cast id to mongoose objectId to make it work

Post.findOneAndUpdate(
   { 'posts.replies._id': _id }, 
   { $set: { 'posts.$[post].replies.$[reply].text': "something1" } },
   { arrayFilters: [{ 'post._id': postId }, { 'reply._id': _id }], new: true }
)
Ashh
  • 44,693
  • 14
  • 105
  • 132
4

As arrayFilters are something related to mongodb, you need to cast id in mongoose with ObjectId

Post.findOneAndUpdate(
   { 'posts.replies._id': _id }, 
   { $set: { 'posts.$[post].replies.$[reply].text': "something1" } },
   { arrayFilters: [{ 'post._id': postId }, { 'reply._id': _id }]}
)

must be changed to

Post.findOneAndUpdate(
   { 'posts.replies._id': _id }, 
   { $set: { 'posts.$[post].replies.$[reply].text': "something1" } },
   { arrayFilters: [{ 'post._id': ObjectId(postId) }, { 'reply._id': ObjectId(_id)}]}
)
0

arrayFilters does not accept stringified Object Ids, as opposed to typical filters in mongoose (which cast object ids automatically for you), you must cast object id manually when passing it as filter to arrayFilters).

Post.findOneAndUpdate(
   { 'posts.replies._id': _id }, 
   { $set: { 'posts.$[post].replies.$[reply].text': "something1" } },
   { arrayFilters: [{ 'post._id':new ObjectId(postId) }, { 'reply._id': new ObjectId(_id) }], new: true }

this will work, check comments here for more details

WadeeSami
  • 59
  • 4