node.jsmongooseupdating

Updating multiple sub-documents with Mongoose and Node


I have a Model which contains an array of sub-documents. This is a Company:

{
"_id" : ObjectId(":58be7c236dcb5f2feff91ac0"),
"name" : "sky srl",

"contacts" : [ 
    {
        "_id" : ObjectId("58be7c236dcb5f2feff91ac2"),
         "name": { type: String, required: true },
        "company" : ObjectId("58be7c236dcb5f2feff91ac0"),
        "email" : "sky@gmail.com",
        "chatId" : "",
        "phone" : "123456789",
        "name" : "John Smith"
    },
    {
        "_id" : ObjectId("58be7f3a6dcb5f2feff91ad3"),
        "company" : ObjectId("58be7f3a6dcb5f2feff91ad1"),
        "email" : "beta@gmail.com",
        "chatId" : "",
        "phone" : "987654321",
        "name" : "Bill Gaset"
    } 
],
    "__v" : 1
}

I have several companies, and I want to update the field chatId of all the contacts in all the companies, that matches the phone I am searching for.

My Schema definitions (simplified, for focusing on question):

var contactSchema = new Schema({
[...]
phone: { type: String, required: true },
email: { type: String },
chatId: { type: String },
company: Schema.Types.ObjectId,
});

var companySchema = new Schema({

name: { type: String, required: true },
type: { type: String, default: "company" },
contacts: [contactSchema]
});

I tried

var conditions = { "contacts.phone": req.body.phone };
var partialUpdate = req.body; //it contains 'req.body.phone' and 'req.body.chatId' attributes
Company.find(conditions).then(
        function (results) {
            results.map( function(companyFound) {
                companyFound.contacts.forEach(function (contactContainer){

                    if (contactContainer.phone == partialUpdate.phone) {
                        contactContainer.chatId = partialUpdate.chatId;

                        Company.save();
                        companyFound.save();
                        contactContainer.save();
                        results.save();
                    }

                    //not sure of what to save, so i save everything
                    companyFound.save();
                    contactContainer.save();
                    results.save();
                });
            });
});

following this answer; but it doesn't works. It does not save anything, what am I doing wrong?


Solution

  • I have never done this before, but worth a try.

    Maybe you need to use $elemMatch.

    // find the companies that have contacts having the phone number
    Company.find().where('contacts', { $elemMatch: { phone: req.body.phone }}).exec(function (err, companies) {
        if (err) {
            console.log(err);
            return;
        }
        // see if you can at least get the query to work
        console.log(companies);
        async.eachSeries(companies, function updateCompany(company, done) {
            // find and update the contacts having the phone number
            company.contacts.forEach(function (contact, i, arr) {
                if (contact.phone == req.body.phone) {
                    arr[i].chatId = req.body.chatId;
                }
            });
            company.save(done);
        }, function allDone (err) {
            console.log(err);
        });
    });
    

    Note, I am using async.js to do async operations on multiple items.

    Honestly, I would have simply made contacts an array of Contact references -- much easier to query and update.