MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Jak znaleźć dokument i pojedynczy poddokument spełniający podane kryteria w kolekcji MongoDB

To, czego szukasz, to pozycyjny $ operator i „rzut”. Dla pojedynczego pola musisz dopasować wymagany element tablicy za pomocą „notacji kropkowej”, dla więcej niż jednego pola użyj $elemMatch :

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

Lub $elemMatch dla więcej niż jednego pasującego pola:

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

Działają one jednak tylko dla jednego elementu tablicy i tylko jeden zostanie zwrócony. Jeśli chcesz, aby więcej niż jeden element tablicy został zwrócony z warunków, potrzebujesz bardziej zaawansowanej obsługi w ramach agregacji.

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" }
    }}
])

Lub ewentualnie w krótszej/szybszej formie od MongoDB 2.6, gdzie tablica elementów zawiera unikalne wpisy:

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

Lub ewentualnie z $redact , ale trochę wymyślony:

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

Bardziej nowoczesny, użyjesz $filter :

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

A przy wielu warunkach $elemMatch i $and w $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 ] }
        ]
      }
    }
  }}
])

Tak więc zależy to tylko od tego, czy zawsze oczekujesz, że jeden element będzie pasował, czy wiele elementów, a następnie, które podejście jest lepsze. Ale tam, gdzie to możliwe, .find() Metoda będzie generalnie szybsza, ponieważ nie ma narzutu innych operacji, co w przypadku ostatnich formularzy wcale nie pozostaje w tyle.

Na marginesie, twoje „daty” są reprezentowane jako ciągi, co nie jest dobrym pomysłem na przyszłość. Zastanów się nad ich zmianą na prawidłową Data typy obiektów, które będą bardzo pomocne w przyszłości.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. mongodb.countDocuments działa wolno, gdy zestaw wyników jest duży, nawet jeśli używany jest indeks

  2. Czy są jakieś powody, dla których powinienem/nie powinienem używać ObjectId w moim adresie URL RESTful

  3. MongoDb:agregacja $lookup z filtrowaniem dokumentów zagranicznych

  4. Czy MongoDB zapewnia unikalne wartości pola _id podczas używania złożonego klucza fragmentu z _id?

  5. Mongoexport błąd parsowania zapytania