MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Prüfen Sie, ob das Feld in einem untergeordneten Dokument eines Arrays vorhanden ist

Sie möchten im Grunde $elemMatch und der $exists Operator, da dieser jedes Element überprüft, um zu sehen, ob die Bedingung "Feld nicht vorhanden" für irgendein Element zutrifft:

Model.find({
  "line_items": {
      "$elemMatch": { "review_request_sent": { "$exists": false } }
  }
},function(err,docs) {

});

Das gibt das zweite Dokument nur zurück, da das Feld nicht in einem der Unterdokumente des Arrays vorhanden ist:

{
        "id" : 2,
        "line_items" : [
                {
                        "id" : 1,
                        "review_request_sent" : false
                },
                {
                        "id" : 39
                }
        ]
}

Beachten Sie, dass sich diese von dieser Form "unterscheidet":

Model.find({
  "line_items.review_request_sent": { "$exists": false } 
},function(err,docs) {

})

Wobei gefragt wird, ob "alle" Array-Elemente dieses Feld nicht enthalten, was nicht zutrifft, wenn ein Dokument mindestens ein Element enthält, in dem das Feld vorhanden ist. Also das $eleMatch bewirkt, dass die Bedingung gegen "jedes" Array-Element getestet wird, und Sie erhalten so die richtige Antwort.

Wenn Sie diese Daten aktualisieren wollten, sodass jedes gefundene Array-Element, das dieses Feld nicht enthielt, dieses Feld mit dem Wert false erhalten sollte ( vermutlich ), dann könnten Sie sogar eine Anweisung wie diese schreiben:

    Model.aggregate(
      [
        { "$match": { 
          "line_items": {
            "$elemMatch": { "review_request_sent": { "$exists": false } }
          } 
        }},
        { "$project": {
          "line_items": {
            "$setDifference": [
              {"$map": {
                "input": "$line_items",
                "as": "item",
                "in": {
                  "$cond": [
                    { "$eq": [ 
                      { "$ifNull": [ "$$item.review_request_sent", null ] },
                      null
                    ]},
                    "$$item.id",
                    false
                  ]
                }
              }},
              [false]
            ]
          }
        }}
    ],
    function(err,docs) {
      if (err) throw err;
      async.each(
        docs,
        function(doc,callback) {
          async.each(
            doc.line_items,
            function(item,callback) {
              Model.update(
                { "_id": doc._id, "line_items.id": item },
                { "$set": { "line_items.$.review_request_sent": false } },
                callback
              );
            },
            callback
          );
        },
        function(err) {
          if (err) throw err;
          // done
        }
      );
    }
  );

Wo die .aggregate() Ergebnis stimmt nicht nur mit den Dokumenten überein, sondern filtert auch Inhalte aus dem Array heraus, in denen das Feld nicht vorhanden war, um nur die "ID" dieses bestimmten Teildokuments zurückzugeben.

Dann die Schleife .update() -Anweisungen stimmen mit jedem gefundenen Array-Element in jedem Dokument überein und fügen das fehlende Feld mit einem Wert an der übereinstimmenden Position hinzu.

Auf diese Weise wird das Feld in allen Unterdokumenten jedes Dokuments vorhanden sein, wo es vorher gefehlt hat.

Wenn Sie so etwas tun möchten, wäre es auch ratsam, Ihr Schema zu ändern, um sicherzustellen, dass das Feld auch immer vorhanden ist:

{id: Number,
  line_items: [{ 
    id: String,
    quantity: Number,
    review_request_sent: { type: Boolean, default: false }
  }],
  total_price: String,
  name: String,
  order_number: Number
}

Wenn Sie also das nächste Mal neue Elemente zum Array in Ihrem Code hinzufügen, wird das Element immer mit seinem Standardwert vorhanden sein, wenn nicht ausdrücklich anders festgelegt. Und es ist wahrscheinlich eine gute Idee, dies zu tun und required zu setzen auf anderen Feldern, die Sie immer wollen, wie z. B. "id".