MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Как да намерите документ и единичен поддокумент, отговарящ на зададени критерии в колекцията MongoDB

Това, което търсите, е позиционният $ оператор и "проекция". За едно поле трябва да съпоставите необходимия елемент от масива, като използвате "точкова нотация", за повече от едно поле използвайте $elemMatch :

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

Или $elemMatch за повече от едно съвпадащо поле:

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

Те обаче работят само за един елемент от масива и ще бъде върнат само един. Ако искате повече от един елемент на масив да бъде върнат от вашите условия, тогава имате нужда от по-разширено боравене с рамката за агрегиране.

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

Или евентуално в по-кратка/по-бърза форма от MongoDB 2.6, където вашият масив от елементи съдържа уникални записи:

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

Или евентуално с $redact , но малко измислено:

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

По-модерно бихте използвали $filter :

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

И с множество условия, $elemMatch и $and в рамките на $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 ] }
        ]
      }
    }
  }}
])

Така че зависи само от това дали винаги очаквате един елемент да съвпада или множество елементи и тогава кой подход е по-добър. Но където е възможно .find() методът като цяло ще бъде по-бърз, тъй като му липсват допълнителните разходи за другите операции, които в тези последни форми изобщо не изостават толкова много.

Като странична бележка, вашите "дати" са представени като низове, което не е много добра идея занапред. Помислете за промяна на тези на правилна Дата типове обекти, което много ще ви помогне в бъдеще.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Има ли библиотека, подобна на orm, за mongodb в scala?

  2. Проблем с агрегирането и групирането на MongoDB в MeteorJS

  3. findAndModify или findOneAndUpdate - не е функция

  4. MongoDB php $in и $regex

  5. MongoDB - различен със заявка не използва индекси