sql >> Databáze >  >> NoSQL >> MongoDB

Jak najít dokument a jeden vnořený dokument odpovídající daným kritériím v kolekci MongoDB

To, co hledáte, je poziční $ operátor a "projekce". Pro jedno pole musíte porovnat požadovaný prvek pole pomocí "tečkové notace", pro více než jedno pole použijte $elemMatch :

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

Nebo $elemMatch pro více než jedno odpovídající pole:

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

Ty však fungují pouze pro jeden prvek pole a vrátí se pouze jeden. Pokud chcete, aby se z vašich podmínek vrátil více než jeden prvek pole, pak potřebujete pokročilejší práci s agregačním rámcem.

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

Nebo možná v kratší/rychlejší podobě od MongoDB 2.6, kde vaše pole položek obsahuje jedinečné položky:

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

Nebo případně pomocí $redact , ale trochu vykonstruované:

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

Modernější byste použili $filter :

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

A s více podmínkami, $elemMatch a $and v rámci $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 ] }
        ]
      }
    }
  }}
])

Záleží tedy jen na tom, zda vždy očekáváte shodu jednoho prvku nebo více prvků, a pak, který přístup je lepší. Ale kde je to možné, .find() Metoda bude obecně rychlejší, protože postrádá režii ostatních operací, které v těchto posledních formulářích vůbec nezaostávají tak daleko.

Jako vedlejší poznámku, vaše "data" jsou reprezentována jako řetězce, což není příliš dobrý nápad do budoucna. Zvažte jejich změnu na správné Datum objektových typů, což vám v budoucnu velmi pomůže.



  1. Lze MongoDB zabalit do aplikace Electron?

  2. Aktualizujte vnořený objekt v MongoDB, pokud existuje, jinak jej přidejte

  3. Node.js detekuje, když je hledání dvou mongoose dokončeno

  4. Jak můžeme zadat dotaz na vložené dokumenty prostřednictvím ovladače java?