Home > other >  RESOLVED - MongoDB $set query in mongoose: Updating an object inside a nested document array [closed
RESOLVED - MongoDB $set query in mongoose: Updating an object inside a nested document array [closed

Time:10-04

I know this has been asked a lot, but I can't get it done via other answers. So could someone help me find the mongoose equivalent of this mongosh query? I have this data:

{ 
data: [ 
  {
    x: 1,
    y: 1
  },
  {
    x: 11,
    y: 11
  },
  {
    x: 111,
    y: 111
  } 
]
}

In order to update a nested object inside an array, I do this in Mongo SH and it works:

*.updateOne({_id: 'ID_HERE', "data.x": 1}, {$set: {"data.$": { x: 2, y: 2 }} })

How would I do this in mongoose? This is how I have ran it

const result = await Positions.updateOne(
            { _id: collectionId, "data.x": 1 },
            {
                $set: {
                    "data.$": { x: 2, y: 2 },
                },
            }
        );

Response from *.updateOne:

{
    "acknowledged": false
}

Response from *.findOneAndUpdate simply returns the same data untouched

Though the update does not happen. Using mongoose v6.0.6

I believe the issue is with the $ position selector. If I change $set to update "data" directly instead of "data.$", it works, but of course, it is not what I want as it replaces the entire data array.

Thank you in advance.

EDIT: Thanks to Joe's answer, I found the problem. The problem was actually in the Schema. data was set as an object instead of array of objects So I updated the Schema from data: {x: Number, y: Number} to data:[{x: Number, y: Number}]

Thanks to everyone who contributed!

CodePudding user response:

This is not a full solution, but it does provide some relevant data that will help find one.

I made a quick test for the code you gave:

const mongoose = require("mongoose");

async function main() {
    await mongoose.connect("mongodb://localhost:27017/");
    const Arrtest = mongoose.model("arrtest",new mongoose.Schema({data:[{}]}));
    const newdoc = await Arrtest.create({ 
        data: [ 
            {
                x: 1,
                y: 1
            },
            {
                x: 11,
                y: 11
            },
            {
                x: 111,
                y: 111
            } 
        ]
    });
    console.log("Mongoose version:", mongoose.version);
    console.log("before:",await Arrtest.findOne({_id:newdoc._id}));
    const result = await Arrtest.updateOne(
        {"_id":newdoc._id, "data.x":1},
        {$set:{
            "data.$":{x:2,y:2}
        }}
    );
    console.log("result:",result); 
    console.log("after:",await Arrtest.findOne({_id:newdoc._id}));

    process.exit(0);
}

main();

The result of running that was:

Mongoose version: 6.0.8
before: {
  _id: new ObjectId("615a995ea3ae207cde4c6984"),
  data: [ { x: 1, y: 1 }, { x: 11, y: 11 }, { x: 111, y: 111 } ],
  __v: 0
}
result: {
  acknowledged: true,
  modifiedCount: 1,
  upsertedId: null,
  upsertedCount: 0,
  matchedCount: 1
}
after: {
  _id: new ObjectId("615a995ea3ae207cde4c6984"),
  data: [ { x: 2, y: 2 }, { x: 11, y: 11 }, { x: 111, y: 111 } ],
  __v: 0
}

This seems to be doing exactly what you wanted, so the problem does not appear to be in the update expression.

Perhaps there is a validation problem, or something mismatching with the Positions model or schema?

CodePudding user response:

can you try :

await Positions.updateOne(
        { _id: collectionId, "data.x": 1 },
        {
                "data.$.x":2 ,
                "data.$.y":2 ,
        }
    );
  • Related