I'm currently building a REST-Api with node.js express and can't figure out how to update / add elements to the scores Array.
Here is one document from my MongoDB collection (how it should look):
My mongoose model:
const challengesSchema = new mongoose.Schema({
createdBy:{
type:String,
required: true
},
mapType:{
type:String,
required: true
},
time:{
type:Number,
required: true
},
numberOfMaps:{
type:String,
required: true
},
maps:{
type:Array,
required: true
},
pin:{
type: String,
required: true
},
takenBy:{
type: Array,
required: false
}
})
Basically I receive an id, which I can use to do Challenges.findById({challenge._id})
. I figured out how to add an object to the takenBy Array
, like so:
Challenges.findOneAndUpdate(
{ _id: challenge._id },
{
$push: {
takenBy: user
}
}
);
How can I add an element (score, like "20") to the scores array in the array 'takenBy' ?
You can push score and calculate the new TotalScore in one go using filtered positional operator $ like this.
router.put("/challenges/:id/:scoreId", async (req, res) => {
let score = req.body.score;
try {
let result = await Challenges.findByIdAndUpdate(
req.params.id,
{
$push: { "takenBy.$[inner].scores": score },
$inc: {
"takenBy.$[inner].TotalScore": score
}
},
{
arrayFilters: [{ "inner._id": req.params.scoreId }],
new: true
}
);
if (!result) return res.status(404);
res.send(result);
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});
Test :
Let's have this existing document:
{
"_id" : ObjectId("5e08fe4c0bc1b932e8726a0f"),
"maps" : [ ],
"takenBy" : [
{
"_id" : "id1",
"TotalScore" : NumberInt(100),
"scores" : [
NumberInt(20),
NumberInt(60),
NumberInt(20)
]
},
{
"_id" : "id2",
"TotalScore" : NumberInt(30),
"scores" : [
NumberInt(10),
NumberInt(20)
]
}
],
"createdBy" : "5dfe0...",
"mapType" : "World",
"time" : NumberInt(2),
"numberOfMaps" : "2",
"pin" : "9558",
"__v" : NumberInt(0)
}
If we want to add a score of 50 to then id1, we send a PUT request ( http://..../challenges/5e08fe4c0bc1b932e8726a0f/id1 ) with this body:
{
"score": 50
}
The result will be like this:
{
"_id" : ObjectId("5e08fe4c0bc1b932e8726a0f"),
"maps" : [ ],
"takenBy" : [
{
"_id" : "id1",
"TotalScore" : NumberInt(150),
"scores" : [
NumberInt(20),
NumberInt(60),
NumberInt(20),
NumberInt(50)
]
},
{
"_id" : "id2",
"TotalScore" : NumberInt(30),
"scores" : [
NumberInt(10),
NumberInt(20)
]
}
],
"createdBy" : "5dfe0...",
"mapType" : "World",
"time" : NumberInt(2),
"numberOfMaps" : "2",
"pin" : "9558",
"__v" : NumberInt(0)
}
As you see the score is added to the related item array, and it's TotalScore is also incremented by 50 giving the TotalScore 150
...how to update / add elements to the scores Array.
I would first retrieve that array... Push the new value, then update.
Something like:
Challenges.findById(challenge._id,(err, db_result) => {
if(err){
console.log(err) // error management
//...
}
if(db_result){
// Get the takenBy array
let takenBy = db_result.takenBy
// Who are we talking about... You need the second _id for that record
let who_id = user._id
let targetIndex = null
let byWho = takenBy.filter((who, index) => {
let gotYa = who._id === who_id
if (gotYa){
targetIndex = index
}
return gotYa // Boolean used as a return for .filter()
})
if(byWho.length>0){
console.log("Got someone... Index: ", targetIndex)
}else{
console.log("No one found?")
return
}
// Push the new value using the index where to update.
takenBy[targetIndex].scores.push(challenge.score)
Challenges.updateOne({_id:challenge._id},{
$set: {
takenBy: takenBy
}
}, (err, data) => {
console.log(data)
}
)
}
});
You can retrieve the object first:
const updateChallenge = async (req,res) => {
const challenge = await Challenges.findById(id);
// Then you make duly changes to it with vanilla js:
// Find which element in the array takenBy to update with regular js, methods
like filter work or hardcode it
challenge.takenBy[1].push(newElement);
await challenge.save();
// DONE! :)
}
Of course you can use destructuring if you prefer!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.