245 votes

Comment mettre partiellement à jour un objet dans MongoDB afin que le nouvel objet se superpose/fusionne avec l'objet existant ?

Étant donné ce document enregistré dans MongoDB

{
   _id : ...,
   some_key: { 
        param1 : "val1",
        param2 : "val2",
        param3 : "val3"
   }
}

Un objet contenant de nouvelles informations sur param2 y param3 du monde extérieur doit être sauvé

var new_info = {
    param2 : "val2_new",
    param3 : "val3_new"
};

Je veux fusionner / superposer les nouveaux champs sur l'état existant de l'objet afin que le paramètre 1 ne soit pas supprimé.

Faire cela

db.collection.update(  { _id:...} , { $set: { some_key : new_info  } } 

MongoDB fait exactement ce qu'on lui a demandé, et définit some_key à cette valeur. en remplaçant l'ancienne.

{
   _id : ...,
   some_key: { 
      param2 : "val2_new",
      param3 : "val3_new"
   }
}

Quel est le moyen de faire en sorte que MongoDB mette à jour uniquement les nouveaux champs (sans les déclarer un par un explicitement) ? pour obtenir ceci :

{
   _id : ...,
   some_key: { 
        param1 : "val1",
        param2 : "val2_new",
        param3 : "val3_new"
   }
}

J'utilise le client Java, mais tout exemple sera apprécié.

0voto

KARTHIKEYAN.A Points 4408

Utiliser $set pour effectuer ce processus

.update({"_id": args.dashboardId, "viewData._id": widgetId}, {$set: {"viewData.$.widgetData": widgetDoc.widgetData}})
.exec()
.then(dashboardDoc => {
    return {
        result: dashboardDoc
    };
});

0voto

Andrew Points 321

Créez un objet de mise à jour avec les noms des propriétés, y compris le chemin de point nécessaire. ("somekey. "+ dans l'exemple de l'OP), puis utilisez cet objet pour effectuer la mise à jour.

//the modification that's requested
updateReq = { 
   param2 : "val2_new",
   param3 : "val3_new"   
}

//build a renamed version of the update request
var update = {};
for(var field in updateReq){
    update["somekey."+field] = updateReq[field];
}

//apply the update without modifying fields not originally in the update
db.collection.update({._id:...},{$set:update},{upsert:true},function(err,result){...});

0voto

Vous devriez penser à mettre à jour l'objet de manière interchangeable et ensuite simplement stocker l'objet avec les champs mis à jour. Quelque chose comme fait ci-dessous

function update(_id) {
    return new Promise((resolve, reject) => {

        ObjModel.findOne({_id}).exec((err, obj) => {

            if(err) return reject(err)

            obj = updateObject(obj, { 
                some_key: {
                    param2 : "val2_new",
                    param3 : "val3_new"
                }
            })

            obj.save((err, obj) => {
                if(err) return reject(err)
                resolve(obj)
            })
        })
    })
}

function updateObject(obj, data) {

    let keys = Object.keys(data)

    keys.forEach(key => {

        if(!obj[key]) obj[key] = data[key]

        if(typeof data[key] == 'object') 
            obj[key] = updateObject(obj[key], data[key])
        else
            obj[key] = data[key]
    })

    return obj
}

0voto

Pavneet Kaur Points 11

Si vous voulez mettre à jour plusieurs champs d'un objet, vous pouvez essayer ceci:-

 let fieldsToUpdate = {};
 for (const key in allFields) {
 const fieldName = `flags.${key}`;   // define field as string literal
     fieldsToUpdate[fieldName] = allFields[key];
 }
 db.collection.updateOne(query, { $set: { ...fieldsToUpdate } } );

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X