2015-10-22 7 views
5

Mam zapytanie, aby uzyskać minimum query i maximum query poniżej zestawu danych próbki. W moim przypadku pól nazwy są dynamiczne, jak poniżej product_1, product_2 ...MongoDB: Wyszukaj minimum, maksimum w obiekcie zagnieżdżonym z nazwą pola dynamicznego

{ 
    "_id" : NumberLong(540), 
    "product_1" : { 
      "orderCancelled" : 0, 
      "orderDelivered" : 6 
    }, 
    "product_2" : { 
      "orderCancelled" : 3, 
      "orderDelivered" : 16 
    }, 
    "product_3" : { 
      "orderCancelled" : 5, 
      "orderDelivered" : 11 
    } 
} 

nie otrzymuję pomysł jak mogę to zrobić w Mongo, gdzie nazwy pól są dynamiczne, czyli w przyszłości może być inna produkty są również tworzone jako product_4 i product_5 dla tego samego id.

muszę zapytać, co dało mi minimalną wartość orderDelivered i maksymalną wartość dla orderCancelled, jak na przykład w wyniku wyżej dokument zostanie orderDelivered:16 & orderCancelled:0.
Dzięki za każdy pomysł.

+0

Dlaczego nie można umieścić swoje produkty do tablicy? –

+0

@DmytroShevchenko Cię nie dostałem. Właściwie w jednym przypadku mogę również podać wartość 'orderDelivered' według' nazwy produktu'. Jaki będzie projekt w twoim przypadku? – Shams

+0

Proszę spojrzeć na przykład struktury danych w mojej odpowiedzi. Czy mógłbyś opisać, co masz na myśli, licząc dla 'orderDelivered' według' nazwy produktu'? –

Odpowiedz

1

Należy zrestrukturyzować swój dokument tak, że wszystkie dokumenty są w produktach tablicy:

{ 
    "_id": NumberLong(540), 
    products: [ 
     { 
      "name": "product_1", 
      "orderCancelled": 0, 
      "orderDelivered": 6 
     }, 
     { 
      "name": "product_2", 
      "orderCancelled": 3, 
      "orderDelivered": 16 
     }, 
     { 
      "name": "product_3", 
      "orderCancelled": 5, 
      "orderDelivered": 11 
     } 
    ] 
} 

Wtedy będziesz w stanie wydawać normalne max/min zapytań tak:

db.test.aggregate([ 
    { 
     $match: { "_id" : NumberLong(540) } 
    }, 
    { 
     $unwind: "$products" 
    }, 
    { 
     $group: { 
      _id: "$_id", 
      minDelivered: { $min: "$products.orderDelivered" }, 
      maxCancelled: { $max: "$products.orderCancelled" } 
     } 
    } 
]) 
+0

co o pokazywaniu, jak zmienić strukturę dokumentów? – styvane

+2

@ user3100115 Istniejące dane należy zmienić za pomocą osobnego narzędzia. Uważam, że omawianie takiego narzędzia nie byłoby tutaj tematem. –

+0

Nie możesz tego zrobić z aktualizacją – styvane

2

You trzeba zmienić strukturę dokumentów, aktualizując je. Będziesz potrzebował przechodzić przez każdy dokument, używając metody .forEach, a następnie $unset nazwy wszystkich pól, które zaczynają się od product_. Tam musisz dodać nowe pola products, które są tablicą produktów przy użyciu operatora aktualizacji $set. Mając na uwadze powyższe należy użyć "bulk" operacji zaktualizować dokumenty dla maksymalnej wydajności

var bulkOp = db.collection.initializeOrderedBulkOp(); 
var count = 0; 
db.collection.find().forEach(function(doc) { 
    var allproducts = []; 
    for(var key in doc) { 
     if(Object.prototype.hasOwnProperty.call(doc, key) && /^product_\d+/.test(key)) { 
      var product = {}; 
      product["name"] = key;  
      product["orderCancelled"] = doc[key]["orderCancelled"]; 
      product["orderDelivered"] = doc[key]["orderDelivered"]; 
      allproducts.push(product); 
      var unsetField = {}; 
      unsetField[key] = ""; 
      bulkOp.find({"_id": doc._id}).update({ "$unset": unsetField }); 
     }; 
     count++; 
    }; 
    bulkOp.find({"_id": doc._id}).update({ 
     "$set": { "products": allproducts } 
    }); 
    count++; 
    if(count % 500 === 0) { 
     // Execute per 500 operations and re-init 
     bulkOp.execute(); 
     bulkOp = db.collection.initializeOrderedBulkOp(); 
    } 
}) 

// clean up queues 

if(count > 0) { 
    bulkOp.execute(); 
} 

Twoje dokumenty będą teraz wyglądać następująco:

{ 
     "_id" : NumberLong(542), 
     "products" : [ 
       { 
         "name" : "product_1", 
         "orderCancelled" : 0, 
         "orderDelivered" : 6 
       }, 
       { 
         "name" : "product_2", 
         "orderCancelled" : 3, 
         "orderDelivered" : 16 
       }, 
       { 
         "name" : "product_3", 
         "orderCancelled" : 5, 
         "orderDelivered" : 11 
       } 
     ] 
} 

Potem przychodzi zapytanie agregacji za pomocą metody .aggregate():

db.collection.aggregate([ 
    { "$match": { "_id": 542 } }, 
    { "$unwind": "$products" }, 
    { "$group": { 
     "_id": "$_id", 
     "maxOrderCancelled": { "$max": "$products.orderCancelled"}, 
     "minOrderDelivvered": { "$min": "$products.orderDelivered"} 
    }} 
]) 

Co zwraca:

{ "_id" : NumberLong(542), "maxOrderCancelled" : 5, "minOrderDelivvered" : 6 } 

Od version 3.2 można użyć $max i $min w etapie $project który jest o wiele bardziej lepszy sposób to zrobić, ponieważ nie ma potrzeby $unwind pierwszej tablicy.

db.collection.aggregate([ 
    { "$match": { "_id": 542 } }, 
    { "$project": { 
     "maxOrderCancelled": { 
      "$max": { 
       "$map": { 
        "input": "$products", 
        "as": "order", 
        "in": "$$orc.orderCancelled" 
       } 
      } 
     }, 
     "minOrderDelivered": { 
      "$min": { 
       "$map": { 
        "input": "$products", 
        "as": "orc", 
        "in": "$$orc.orderDelivered" 
       } 
      } 
     } 
    }} 
]) 

co daje:

{ "_id" : NumberLong(542), "maxOrderCancelled" : 5, "minOrderDelivered" : 6 } 
Powiązane problemy