sql >> Database >  >> NoSQL >> MongoDB

Controleer of het veld bestaat in een subdocument van een array

Je wilt eigenlijk $elemMatch en de $exists operator, omdat dit elk element zal inspecteren om te zien of de voorwaarde "veld niet bestaat" waar is voor elk element:

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

});

Dat retourneert alleen het tweede document omdat het veld niet aanwezig is in een van de array-subdocumenten:

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

Merk op dat dit "afwijkt" van dit formulier:

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

})

Waar dat is vragen, bevatten "alle" array-elementen dit veld niet, wat niet waar is wanneer een document ten minste één element heeft waarin het veld aanwezig is. Dus de $eleMatch zorgt ervoor dat de voorwaarde wordt getest tegen "elk" array-element, en zo krijg je het juiste antwoord.

Als u deze gegevens wilt bijwerken zodat elk gevonden array-element dat dit veld niet bevat, dat veld zou ontvangen met de waarde false ( vermoedelijk ), dan zou je zelfs een verklaring als deze kunnen schrijven:

    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
        }
      );
    }
  );

Waar de .aggregate() resultaat komt niet alleen overeen met de documenten, maar filtert ook inhoud uit de array waar het veld niet aanwezig was, om gewoon de "id" van dat specifieke subdocument te retourneren.

Dan de lusvormige .update() statements komen overeen met elk gevonden array-element in elk document en voegen het ontbrekende veld toe met een waarde op de overeenkomende positie.

Op die manier heb je het veld aanwezig in alle subdocumenten van elk document waar het voorheen ontbrak.

Als je zoiets wilt doen, is het ook verstandig om je schema te wijzigen om ervoor te zorgen dat het veld er ook altijd is:

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

Dus de volgende keer dat u nieuwe items aan de array in uw code toevoegt, zal het element altijd bestaan ​​met zijn standaardwaarde, tenzij anders expliciet ingesteld. En het is waarschijnlijk een goed idee om dit te doen, evenals het instellen van required op andere velden die u altijd wilt, zoals "id".



  1. MongoDB $toString

  2. MongoDB $log10

  3. mongodb tel tellen zonder te herhalen vinden

  4. Hoe een waarde uit mongoDB op te halen, op basis van de sleutelnaam?