2017-01-26 2 views
3

У меня есть коллекция Монго продуктов с атрибутами:Получить счетчик атрибуты продукта из MongoDB

{ 
    "_id" : ObjectId("5888a2860c001d31a1089958"), 
    "product_id" : "107", 
    "store_id" : 0, 
    "attributes" : [{ 
     "key" : "m", 
     "value" : 21, 
     "label" : "Mothercare" 
    }, { 
     "key" : "sp", 
     "value" : 10.0, 
     "label" : 10.0 
    }, { 
     "key" : "pr", 
     "value" : 2, 
     "label" : "150-300" 
    }, { 
     "key" : "c", 
     "value" : 59, 
     "label" : "Category 1" 
    }, { 
     "key" : "c", 
     "value" : 86, 
     "label" : "Category 2" 
    }, { 
     "key" : "c", 
     "value" : 134, 
     "label" : "Category 3" 
    }, { 
     "key" : "c", 
     "value" : 1013, 
     "label" : "Category 4" 
    }, { 
     "key" : "c", 
     "value" : 1063, 
     "label" : "Category 5" 
    }, { 
     "key" : "c", 
     "value" : 1073, 
     "label" : "Category 6" 
    }, { 
     "key" : "13", 
     "value" : 270, 
     "label" : "Brown" 
    }, { 
     "key" : "18", 
     "value" : 125, 
     "label" : "Girl" 
    }, { 
     "key" : "19", 
     "value" : 298, 
     "label" : "0-3 month" 
    }, { 
     "key" : "19", 
     "value" : 299, 
     "label" : "3-6 month" 
    }, { 
     "key" : "19", 
     "value" : 300, 
     "label" : "6-9 month" 
    }, { 
     "key" : "19", 
     "value" : 301, 
     "label" : "9-12 month" 
    }] 
} 

Мне нужно найти быстрый способ для подсчета ПОЛУЧИТЬ все атрибуты в коллекции. Я пытался использовать MapReduce:

function map() { 
    var max = this.attributes.length; 
    var key = {}; 

    for (var i = 0; i < max; i++) { 
     key = { 
      key: this.attributes[i]['key'], 
      value: this.attributes[i]['value'], 
     } 

     emit(key, {count: 1}); 
    } 
} 
function reduce(key, values) { 
    var sum = 0; 
    values.forEach(function(value) { 
     sum += value['count']; 
    }); 
    return {count: sum}; 
}; 

Но это очень медленно:

timeMillis=2420 
counts={ "input" : 18963, "emit" : 221232, "reduce" : 7341, "output" : 1289 } 

Как я могу найти количество всех атрибутов быстрее? Мне нужно это для фильтра продукта. Может быть, я должен использовать другую структуру коллекции?

не нужно найти общее количество атрибутов, мне нужно найти подсчет каждого атрибута, например:
{ «ключ»: «с», «значение»: 59} имеет 2345 продукты
{ «ключ»: «м», «значение»: 21} имеет 258 продуктов

ответ

1

Запуск следующего трубопровода даст вам желаемый результат:

db.collection.aggregate([ 
    { "$unwind": "$attributes" }, 
    { 
     "$group": { 
      "_id": { 
       "key": "$attributes.key", 
       "value": "$attributes.value" 
      }, 
      "counts": { "$sum": 1 } 
     } 
    } 
]) 

Для более эффективного запроса, используйте агрегацию фреймворк. Рассмотрим запуск трубопровода с $project, чтобы получить количество атрибутов в документе с помощью $size оператора на attributes массива, а затем окончательное $group трубопровода, где вы можете указать _id значение NULL для расчета суммарных значений для всех входные документы в целом и рассчитать общий подсчет с использованием $sum следующим образом:

db.collection.aggregate([ 
    { 
     "$project": { 
      "counts": { 
       "$size": "$attributes" 
      } 
     }  
    }, 
    { 
     "$group": { 
      "_id": null, 
      "counts": { "$sum": "$counts" } 
     } 
    } 
]) 

выше будет возвращать общее количество ttributes всех продуктов в коллекции.


Если вы хотите использовать количество атрибутов для фильтрации продукта, а затем рассмотреть вопрос об использовании $redact трубопровода как:

var attributeCount = 12; // for example 
db.collection.aggregate([ 
    { 
     "$redact": { 
      "$cond": [ 
       { "$eq": [ { "$size": "$attributes" }, attributeCount ] }, 
       "$$KEEP", 
       "$$PRUNE" 
      ] 
     }  
    } 
]) 

Это эквивалентно комбинации $project и $match трубопровод, хотя вы не должны указывать все поля в $project трубопровода, как в следующем:

db.collection.aggregate([ 
    { 
     "$project": { 
      "product_id": 1, 
      "store_id": 1, 
      "$attributes": 1, 
      "counts": { 
       "$size": "$attributes" 
      } 
     }  
    }, 
    { "$match": { "counts": { "$gte": attributeCount } } } 
]) 

+0

не нужно найти общее количество атрибутов, мне нужно найти количество каждого атрибута, например: { «ключ»: «C», «значение»: 59} имеет 2345 продуктов { " ключ ":" m "," value ": 21} имеет 258 продуктов – gvozd1989

+0

О, был полностью удален. Спасибо за обновление. В этом случае вам нужен конвейер '$ unwind' и' $ group', как в приведенном выше обновлении. – chridam

0

Чтобы получить общее кол-attributes по ключа значение пары может попробовать этот запрос.

db.collectionName.aggregate([ 
    {$unwind:{"$attributes"}} 
    {$group: { 
      _id: {"key": "$attributes.key","value": "$attributes.value"}, 
      count: { $sum: 1 } 
     } 
    }, 
    {$project:{ 
     key:"$_id.key", 
     value:"$_id.value", 
     count:1 
     } 
    } 
]) 
Смежные вопросы