sql >> Database teknologi >  >> NoSQL >> MongoDB

Sådan finder du dokument og enkelt underdokument, der matcher givne kriterier i MongoDB-samlingen

Det, du leder efter, er den positionelle $ operatør og "projektion". For et enkelt felt skal du matche det påkrævede array-element ved hjælp af "dot notation", for mere end ét felt skal du bruge $elemMatch :

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

Eller $elemMatch for mere end ét matchende felt:

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

Disse virker dog kun for et enkelt array-element, og kun ét vil blive returneret. Hvis du ønsker, at mere end ét array-element skal returneres fra dine betingelser, har du brug for mere avanceret håndtering med aggregeringsrammerne.

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

Eller muligvis i kortere/hurtigere form siden MongoDB 2.6, hvor dit udvalg af varer indeholder unikke poster:

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

Eller muligvis med $redact , men lidt fortænkt:

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

Mere moderne ville du bruge $filter :

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

Og med flere betingelser er $elemMatch og $and i $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 ] }
        ]
      }
    }
  }}
])

Så det afhænger bare af, om du altid forventer, at et enkelt element matcher eller flere elementer, og så hvilken tilgang der er bedre. Men hvor det er muligt .find() metoden vil generelt være hurtigere, da den mangler overhead af de andre operationer, som i de sidste til former slet ikke halter så langt bagud.

Som en sidebemærkning er dine "datoer" repræsenteret som strenge, hvilket ikke er en særlig god idé fremover. Overvej at ændre disse til korrekte Dato objekttyper, som i høj grad vil hjælpe dig i fremtiden.



  1. Forskel mellem Redis AOF og Tarantool WAL log

  2. PHP intl.so mislykkes

  3. C# MongoDB:Hvordan kortlægger man et domæneobjekt korrekt?

  4. MongoDB 2.6 Aggregation Framework Forbedringer