简体   繁体   中英

Mongoose updating nested subdocuments

I am trying to update sub documents with mongoose using the request.body without passing of the sub documents _id . Updating works but mongoose is removing the _id from the sub documents.

Assume the following schemas

// schemas.js
const mongoose = require('mongoose');

const motorSchema = new mongoose.Schema({
    type: String,
    volume: Number,
});

const carSchema = new mongoose.Schema({
    manufacturer: String,
    model: String,
    motors: [motorSchema],
});

const userSchema = new mongoose.Schema({
   username: String,
   email: String,
   cars: [carSchema]
});
const mongoose = require('mongoose');
// import schemas
const userSchema = require('userSchema');
const carSchema = require('carSchema');
const motorSchema = require('motorSchema');
// create models
const User = mongoose.model("User", userSchema);
const Car = mongoose.model("Car", carSchema);
const Motor = mongoose.model("Motor", motorSchema);

module.exports.updateCar = async function (request, response) {
    const condition = {
        _id: new mongoose.Types.ObjectId(request.body.userId),
        "cars._id": new mongoose.Types.ObjectIt(request.body.carId)
        };

    // Build object for partial update
    const set = {};
    for(let field in reqest.body){
        set[`cars.$.${field}`] = request.body[field];
    }

    const update = {
        $set = set;
    }

    User.findOneAndUpdate(condition, update, {new: true, overwrite: false},
        (error, user) => {
            if(error) {response.send(error)}
            response.json(user);
        }
}

The problem is that all my _id properties will be overwritten in the motors array. How can I force mongoose as default to not change the _id properties?

If I understand you correctly, the equivalent mongoDB syntax will use arrayFilters , so you can modify your query to use that as well:

For example:

User.findOneAndUpdate(
  condition,
  {$set: {"cars.$[item].size": "large"}},
  {arrayFilters: [{"item._id": new mongoose.Types.ObjectIt(request.body.carId)}]}
)

See how it works on the playground example

According to this method, your code needs the arrayFilters in the options part and the $[<identifier>] in the $set part of the query:

const set = {};
    for(let field in reqest.body){
        set[`cars.$[item].${field}`] = request.body[field];
    }

    const update = {
        $set = set;
    }

    User.findOneAndUpdate(
        condition, 
        update, 
        {
            arrayFilters: [{"item._id": new mongoose.Types.ObjectIt(request.body.carId)}],
            new: true, overwrite: false
        },
        (error, user) => {
            if(error) {response.send(error)}
            response.json(user);
        }

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM