2014-08-30 13 views
11

Ho una raccolta di prodotti. Ogni prodotto contiene una serie di elementi.Come trovare il documento e il singolo documento secondario corrispondenti ai criteri specificati nella raccolta MongoDB

> db.products.find().pretty() 
{ 
    "_id" : ObjectId("54023e8bcef998273f36041d"), 
    "shop" : "shop1", 
    "name" : "product1", 
    "items" : [ 
      { 
        "date" : "01.02.2100", 
        "purchasePrice" : 1, 
        "sellingPrice" : 10, 
        "count" : 15 
      }, 
      { 
        "date" : "31.08.2014", 
        "purchasePrice" : 10, 
        "sellingPrice" : 1, 
        "count" : 5 
      } 
    ] 
} 

Così, potete per favore darmi un consiglio, come posso interrogare MongoDB per recuperare tutti i prodotti con solo un'unica voce che data è uguale alla data passo per interrogare come parametro.

Il risultato per "2014/08/31" deve essere:

{ 
    "_id" : ObjectId("54023e8bcef998273f36041d"), 
    "shop" : "shop1", 
    "name" : "product1", 
    "items" : [ 
      { 
        "date" : "31.08.2014", 
        "purchasePrice" : 10, 
        "sellingPrice" : 1, 
        "count" : 5 
      } 
    ] 
} 
+0

Utilizzare '$ filter' a partire da 3.2. Più qui https://stackoverflow.com/questions/3985214/retrieve-only-the-queried-element-in-an-object-array-in-mongodb-collection – Veeram

risposta

26

Quello che state cercando è the positional $ dell'operatore e "proiezione". Per un singolo campo è necessario abbinare l'elemento array desiderata con "la notazione punto", per più di un uso sul campo $elemMatch:

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

O la $elemMatch per il campo più di una corrispondenza:

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

Questi funzionano solo per un singolo elemento dell'array e solo uno verrà restituito. Se si desidera che più di un elemento dell'array venga restituito dalle condizioni, è necessaria una gestione più avanzata con il framework di aggregazione.

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

O forse in forma più breve/più veloce dal MongoDB 2.6 in cui la matrice di elementi contiene voci univoche:

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

O forse con $redact, ma un po 'forzato:

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

Quindi dipende solo dal fatto che ci si aspetti sempre che un singolo elemento corrisponda o più elementi, e quindi quale sia l'approccio migliore. Ma se possibile, il metodo .find() sarà generalmente più veloce poiché manca il sovraccarico delle altre operazioni, che in quelle ultime alle forme non sono affatto così indietro.

Come nota a margine, le "date" sono rappresentate come stringhe che non è una buona idea per il futuro. Valuta la possibilità di cambiarli in opportuni tipi di oggetto Date, che ti saranno di grande aiuto in futuro.

+0

Grazie! Bella risposta! È sicuramente quello che stavo cercando e anche di più. – evgeniy44

+0

Grazie. Lo hai spiegato in dettaglio –

0

Mongo supporta la notazione punto per le sottoquery.

See: http://docs.mongodb.org/manual/reference/glossary/#term-dot-notation

seconda del driver, si desidera qualcosa di simile:

db.products.find({"items.date":"31.08.2014"}); 

Si noti che l'attributo è tra virgolette per notazione del punto, anche se di solito il driver non richiede questo.

Problemi correlati