Emiel Vandenbussche
Emiel Vandenbussche

Reputation: 383

mongoose update item in array by position/index

Is there a way to update for example the second item in an array with mongoose?

Schema:

title: String,
answer: [{
    content: String,
    votes: Number
}]

In my case I want to update the first or second answer, so it has 1 vote more.

Upvotes: 5

Views: 13757

Answers (3)

SAUMITRA KUMAR
SAUMITRA KUMAR

Reputation: 767

Try this .I hope this will work

Model.findOneAndUpdate({query},{["answer.${element index}.content:new_data"]},{new:true},(err,docs)=>{})

Upvotes: 2

yaoxing
yaoxing

Reputation: 4183

I'm not a mongoose expert. But there seems to be some answer you can reference.
So the short answer is yes, you can update an array element by specify its index. In shell it would be:

db.collection.update({...}, {$inc: {"answer.0.votes": 1}})

where 0 is the index of element you want to update. I'm sure you can find corresponding grammar how to write this in mongoose.

In my opinion, to update an array by its index is not really a good idea. What if an element is removed/inserted? Your embedded array element is like a one to many relation in a RDBMS. They should have unique identifier like an ObjectId to be located more easily. Suggested data structure:

{
    title: "This is a question",
    answer: [{
        id: ObjectId("584e6c496c9b4252733ea6fb"),
        content: "Answer",
        votes: 0
    }]
}

And query by id to find the exact answer you are voting up:

db.collection.update({"answer": {$elemMatch: {id: ObjectId("584e6c496c9b4252733ea6fb")}}}, {$inc: {"answer.$.votes": 1}});

where $ means the matched element in the array.

edit - 2018-04-03

  1. if there's only one condition, $elemMatch is not necessary. It's meant for matching 2 or more conditions in one element. Without $elemMatch, different conditions may match different element in the array. Which is not expected in most scenarios.
  2. As of 3.6 MongoDB introduced $[], which allows you to update all elements in an array in one update.

Upvotes: 8

Divyanshu Maithani
Divyanshu Maithani

Reputation: 14986

Try this:

Model.findOne({ title: 'your-title' }, function (err, doc){
  doc.answer.0.votes.$inc(); // increases votes on first answer by 1
  doc.save();
});

Upvotes: 1

Related Questions