sql >> Database >  >> NoSQL >> MongoDB

Hoe u een document en een enkel subdocument kunt vinden dat overeenkomt met bepaalde criteria in de MongoDB-verzameling

Wat u zoekt is de positionele $ operator en "projectie". Voor een enkel veld moet u overeenkomen met het vereiste array-element met behulp van "dot-notatie", voor meer dan één veld gebruikt u $elemMatch :

db.products.find(
    { "items.date": "31.08.2014" },
    { "shop": 1, "name":1, "items.$": 1 }
)

Of de $elemMatch voor meer dan één overeenkomend veld:

db.products.find(
    { "items":  { 
        "$elemMatch": { "date": "31.08.2014",  "purchasePrice": 1 }
    }},
    { "shop": 1, "name":1, "items.$": 1 }
)

Deze werken echter alleen voor een enkel array-element en er wordt er maar één geretourneerd. Als u meer dan één array-element wilt retourneren uit uw voorwaarden, dan heeft u meer geavanceerde verwerking nodig met het aggregatieraamwerk.

db.products.aggregate([
    { "$match": { "items.date": "31.08.2014" } },
    { "$unwind": "$items" },
    { "$match": { "items.date": "31.08.2014" } },
    { "$group": {
        "_id": "$_id",
        "shop": { "$first": "$shop" },
        "name": { "$first": "$name" },
        "items": { "$push": "$items" }
    }}
])

Of mogelijk in kortere/snellere vorm sinds MongoDB 2.6 waar uw reeks items unieke items bevat:

db.products.aggregate([
    { "$match": { "items.date": "31.08.2014" } },
    { "$project": {
        "shop": 1,
        "name": 1,
        "items": {
            "$setDifference": [
                { "$map": {
                    "input": "$items",
                    "as": "el",
                    "in": {
                        "$cond": [
                            { "$eq": [ "$$el.date", "31.08.2014" ] },
                            "$$el",
                            false 
                        ]
                    }
                }},
                [false]
            ]
        }
    }}
])

Of eventueel met $redact , maar een beetje gekunsteld:

db.products.aggregate([
    { "$match": { "items.date": "31.08.2014" } },
    { "$redact": {
        "$cond": [
             { "$eq": [ { "$ifNull": [ "$date", "31.08.2014" ] }, "31.08.2014" ] },
             "$$DESCEND",
             "$$PRUNE"
         ]
    }}
])

Moderner, je zou $filter . gebruiken :

db.products.aggregate([
  { "$match": { "items.date": "31.08.2014" } },
  { "$addFields": {
    "items": {
      "input": "$items",
      "cond": { "$eq": [ "$$this.date", "31.08.2014" ] }
    }
  }}
])

En met meerdere voorwaarden, de $elemMatch en $and binnen de $filter :

db.products.aggregate([
  { "$match": { 
    "$elemMatch": { "date": "31.08.2014",  "purchasePrice": 1 }
  }},
  { "$addFields": {
    "items": {
      "input": "$items",
      "cond": { 
        "$and": [
          { "$eq": [ "$$this.date", "31.08.2014" ] },
          { "$eq": [ "$$this.purchasePrice", 1 ] }
        ]
      }
    }
  }}
])

Het hangt er dus gewoon van af of je altijd verwacht dat een enkel element overeenkomt of meerdere elementen, en welke aanpak dan beter is. Maar waar mogelijk de .find() methode zal over het algemeen sneller zijn omdat het de overhead van de andere bewerkingen mist, die in die laatste tot formulieren helemaal niet zo ver achterblijven.

Terzijde:je "datums" worden weergegeven als strings, wat in de toekomst geen goed idee is. Overweeg deze te wijzigen in de juiste Datum objecttypes, die u in de toekomst enorm zullen helpen.



  1. Server x time-out tijdens MongoDB-aggregatie

  2. Hoogwaardige MongoDB-clusters op Amazon EC2

  3. opdrachtregelauthenticatie van mongo mislukt

  4. afbeeldingen opslaan in mongodb met behulp van mangoest ?? hoe?