MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

mettre à jour l'objet imbriqué à deux couches en fonction de l'identifiant

Vous pouvez réellement résoudre votre problème avec la mise à jour méthode, mais vous devez le faire d'une manière différente si vous utilisez MongoDB 4.2 ou une version ultérieure. Le deuxième paramètre peut être le $set opération que vous souhaitez effectuer ou une aggregation pipeline. En utilisant le dernier, vous avez plus de liberté pour façonner les données. C'est ainsi que vous pouvez résoudre votre problème, je vais m'effondrer après :

db.collection.update({
  "cards.advanced.unit": 2
},
[
  {
    $set: {
      "cards.advanced": {
        $map: {
          input: "$cards.advanced",
          as: "adv",
          in: {
            cards: {
              $map: {
                input: "$$adv.cards",
                as: "advcard",
                in: {
                  $cond: [
                    {
                      $eq: [
                        "$$advcard.id",
                        "main-2-1"
                      ]
                    },
                    {
                      title: "this is a NEW updated card",
                      id: "$$advcard.id"
                    },
                    "$$advcard"
                  ]
                }
              }
            },
            unit: "$$adv.unit"
          }
        }
      }
    }
  }
],
{
  new: true,
  
});

Utilisez d'abord la mise à jour méthode passant trois paramètres :

  • Filtrer la requête
  • Pipeline d'agrégation
  • Options. Ici, je viens d'utiliser new: true pour renvoyer le document mis à jour et faciliter le test.

Voici la structure :

db.collection.update({
  "cards.advanced.unit": 2
},
[
  // Pipeline
],
{
  new: true,
});

À l'intérieur du pipeline, nous n'avons besoin que d'une étape, le $set pour remplacer la propriété advanced avec un tableau que nous allons créer.

...
[
  {
    $set: {
      "cards.advanced": {
        // Our first map
      } 
    }
  }
]
...

Nous mappons d'abord l'élément advanced tableau pour pouvoir mapper le tableau des cartes imbriquées après :

...
[
  {
    $set: {
      "cards.advanced": {
        $map: {
          input: "$cards.advanced",
          as: "adv",
          in: {
            // Here we will map the nested array
          }
        }     
      } 
    }
  }
]
...

Nous utilisons la variable que nous avons déclarée sur la première carte et qui contient l'élément actuel du tableau avancé en cours de mappage ( adv ) pour accéder et mapper le tableau "cards" imbriqué ( $$adv.cards ):

...
[
  {
    $set: {
      "cards.advanced": {
        $map: {
          input: "$cards.advanced",
          as: "adv",
          in: {
            cards: {
              $map: {
                input: "$$adv.cards",
                as: "advcard",
                in: {
                // We place our condition to check for the chosen card here
                }
              }
            },
            unit: "$$adv.unit",
          }
        }     
      } 
    }
  }
]
...

Enfin, nous vérifions si l'identifiant de la carte actuelle est égal à l'identifiant recherché $eq: [ "$$advcard.id", "main-2-1" ] et retournez la nouvelle carte si elle correspond ou la carte actuelle :

...
{
  $cond: [
    {
      $eq: [
        "$$advcard.id",
        "main-2-1"
      ]
    },
    {
      title: "this is a NEW updated card",
      id: "$$advcard"
    },
    "$$advcard"
  ]
}

...

Voici un exemple concret de ce qui est décrit :https://mongoplayground.net/p/xivZGNeD8ng