Mettre à jour le tableau imbriqué avec Mongoose – MongoDB

J'essaie de mettre à jour une valeur dans le tableau imbriqué mais je ne peux pas le faire fonctionner.

Mon objet est comme celui-ci

{ "_id": { "$oid": "1" }, "array1": [ { "_id": "12", "array2": [ { "_id": "123", "answeredBy": [], }, { "_id": "124", "answeredBy": [], } ], } ] } 

J'ai besoin d'appuyer sur une valeur pour le réseau "AnswerBy".

Dans l'exemple ci-dessous, j'ai essayé de pousser la chaîne de "succès" dans le tableau "AnswerBy" de l'objet "123 _id", mais cela ne fonctionne pas.

 callback = function(err,value){ if(err){ res.send(err); }else{ res.send(value); } }; conditions = { "_id": 1, "array1._id": 12, "array2._id": 123 }; updates = { $push: { "array2.$.answeredBy": "success" } }; options = { upsert: true }; Model.update(conditions, updates, options, callback); 

J'ai trouvé ce lien , mais sa réponse indique seulement que je devrais utiliser l'objet comme la structure au lieu de la matrice. Cela ne peut pas être appliqué dans ma situation. J'ai vraiment besoin de mon objet d'être imbriqué dans les tableaux

Ce serait génial de pouvoir m'aider ici. J'ai passé des heures à comprendre cela.

Merci d'avance!

Il y a quelques malentendus avec ce que vous faites ici. Tout d'abord, vos conditions de requête. Vous parlez de plusieurs valeurs _id où vous ne devriez pas avoir besoin, et au moins une d'entre elles n'est pas au niveau supérieur.

Pour entrer dans une valeur "imbriquée" et en supposant que la valeur _id est unique et n'apparaitrait pas dans un autre document, le formulaire de requête devrait être comme suit:

 Model.update( { "array1.array2._id": "123" }, { "$push": { "array1.0.array2.$.answeredBy": "success" } }, function(err,numAffected) { // something with the result in here } ); 

Maintenant, cela fonctionnerait réellement, mais vraiment, ce n'est qu'un problème, car il existe de très bonnes raisons pour lesquelles cela ne devrait pas fonctionner pour vous.

La lecture importante se trouve dans la documentation officielle de l'opérateur positionnel $ sous la rubrique "Arrays imbriqués". Ce que cela dit est:

L'opérateur positionnel $ ne peut pas être utilisé pour les requêtes qui traversent plus d'un tableau, telles que les requêtes qui traversent des tableaux imbriqués dans d'autres tableaux, car le remplacement de l'espace réservé $ est une valeur unique

Plus précisément, cela signifie que l'élément qui sera adapté et renvoyé dans l'espace réservé positionnel est la valeur de l'index à partir du premier groupe correspondant. Cela signifie dans votre cas l'indice correspondant sur le tableau de niveau "supérieur".

Donc, si vous regardez la notation de la requête comme indiqué, nous avons "codé en dur" la première position (ou 0) dans le tableau de niveau supérieur, et il se trouve que l'élément correspondant dans "array2" est également l'entrée d'index zéro.

Pour démontrer cela, vous pouvez modifier la valeur _id correspondante à "124" et le résultat $push une nouvelle entrée sur l'élément avec _id "123" car ils sont à la fois dans l'entrée d'index zéro de "array1" et c'est la valeur retournée À l'espace réservé.

C'est donc le problème général avec les réseaux de nidification. Vous pouvez supprimer l'un des niveaux et vous pourriez toujours $push vers l'élément correct dans votre tableau "supérieur", mais il y aurait toujours plusieurs niveaux.

Essayez d'éviter les arrachages de nidification, car vous allez rencontrer des problèmes de mise à jour tel qu'indiqué.

Je sais que c'est une question très ancienne, mais j'ai simplement lutté avec ce problème, et j'ai trouvé, ce que je crois être, une meilleure réponse.

Une façon de résoudre ce problème consiste à utiliser des Sub-Documents . Cela se fait en imbriquant des schémas dans vos schémas

 MainSchema = new mongoose.Schema({ array1: [Array1Schema] }) Array1Schema = new mongoose.Schema({ array2: [Array2Schema] }) Array2Schema = new mongoose.Schema({ answeredBy": [...] }) 

De cette façon, l'objet ressemblera à celui que vous montrez, mais maintenant, chaque tableau est rempli de sous-documents. Cela permet de parcourir le sous-document que vous souhaitez. Au lieu d'utiliser un .update vous utilisez un .find ou .findOne pour obtenir le document que vous souhaitez mettre à jour.

 Main.findOne(( { _id: 1 } ) .exec( function(err, result){ result.array1.id(12).array2.id(123).answeredBy.push('success') result.save(function(err){ console.log(result) }); } ) 

.push( pas moi-même la fonction .push( ), donc la syntaxe pourrait ne pas être correcte, mais j'ai utilisé les deux .set() et .remove() , et les deux fonctionnent parfaitement.