Агрегатный массив массива MongoDB как группа _id

У меня возникли проблемы с использованием структуры агрегации MongoDB для подсчета типов событий в моей базе данных. Как рассчитать сумму value.count поле для каждого уникального третьего индекса _id.val поле?

Основная структура моих данных выглядит так:

{ _id: { evt: "click", val: [ "default", "125", "311", "1" ] }, value: { count: 1 } }
{ _id: { evt: "click", val: [ "default", "154", "321", "2" ] }, value: { count: 2 } }
{ _id: { evt: "click", val: [ "default", "192", "263", "1" ] }, value: { count: 4 } }

Значения в val поле обозначает ["type","x","y","time"]соответственно.
Я пытаюсь извлечь третий индекс, или time значение _id.val ключ. Результат, который я ищу для достижения:

 1: 5
2: 2

Я пытался сделать это через этот PHP:

$ops2 = array(
array(
'$match' => $q2
),
array(
'$group' => array(
'_id' => array(
'evt' => '$_id.evt',
'time' => '$_id.val.3'
),
'count' => array('$sum' => '$value.count' )
)
)
);

Но это не похоже на 3 индекс в групповом массиве

2

Решение

Во-первых, я думаю, что у вас может быть что-то не так в вашем понимании Монго … Потому что каждый документ в монго должен иметь свой уникальный _id, чтобы идентифицировать себя с другими. Поэтому я добавил _id к каждому объекту и изменил поле вашего происхождения «_id» на «data». Теперь структура:

/* 1 */
{
"_id" : "ubLrDptWvJE7LZqDF",
"data" : {
"evt" : "click",
"val" : [ "default", "125", "311", "1" ]
},
"value" : {
"count" : 1
}
}

/* 2 */
{
"_id" : "C2QCEhvCsp3xG6EKZ",
"data" : {
"evt" : "click",
"val" : [ "default", "154", "321", "2" ]
},
"value" : {
"count" : 2
}
}

/* 3 */
{
"_id" : "bT72z7gMKoyX5JfHL",
"data" : {
"evt" : "click",
"val" : [ "default", "192", "263", "1" ]
},
"value" : {
"count" : 4
}
}

Я не уверен, как сделать этот запрос в PHP, потому что я немного знаю PHP …… Но я мог бы привести пример использования агрегации в Javascript, его код и вывод выглядят следующим образом:
код и вывод

Вот несколько полезных ссылок: используя монго в PHP
Я хотел бы, чтобы это помогло вам решить вашу проблему отлично 🙂

1

Другие решения

Данные, с которыми вы работаете, выглядят так, как будто они уже являются результатом операции mapReduce, поскольку они имеют ту конкретную структуру «_id» и «value», которую выполняет mapReduce. Таким образом, вам лучше вернуться к логике реализации этого процесса и следовать тому же, чтобы просто извлечь и суммировать то, что вы хотите, или, по крайней мере, изменить форму вывода на следующую:

{
_id: {
evt: "click",
val: { "type": "default", "x": "125", "y": "311", "time": "1" }
},
value: { count: 1 }
},
{
_id: {
evt: "click",
val: { "type": "default", "x": "154", "y": "321", "time": "2" }
},
value: { count: 2 }
},
{
_id: {
evt: "click",
val: { "type": "default", "x": "192", "y": "263", "time": "1" }
},
value: { count: 4 }
}

Поскольку проблема заключается в том, что инфраструктуре агрегирования «в настоящее время» не хватает возможности обратиться к «индексированной» позиции массива (реальный «неассоциативный» массив, а не массив PHP) и всегда будет возвращать null когда ты пытаешься сделать это.

Не имея возможности вернуться к исходной операции source или mapReduce, вы можете написать операцию mapReduce для этих данных, чтобы получить ожидаемые результаты (представление оболочки, так как в любом случае это будет JavaScript):

db.collection.mapReduce(
function() {
emit({ evt: this._id.evt, time: this._id.val[3] }, this.value.count)
},
function(key,values) {
return Array.sum(values)
},
{ out: { inline: 1 } }
)

Который возвращает типичный вывод mapReduce следующим образом:

{
"_id" : {
"evt" : "click",
"time" : "1"},
"value" : 5
},
{
"_id" : {
"evt" : "click",
"time" : "2"},
"value" : 2
}

Если бы вы смогли по крайней мере преобразовать текущую коллекцию выходных данных в форму, предложенную вначале выше, вы бы вместо этого работали с такой структурой агрегирования (снова общее представление):

    { "$group": {
"_id": {
"evt": "$_id.evt",
"time": "$_id.val.time"},
"count": { "$sum": "$value.count" }
}}

Что, конечно, получится из измененных данных:

{ "_id" : { "evt" : "click", "time" : "2" }, "count" : 2 }
{ "_id" : { "evt" : "click", "time" : "1" }, "count" : 5 }

В будущих выпусках MongoDB будет $slice оператор, который разрешает обработку массива, поэтому с вашей текущей структурой вы можете сделать это вместо этого:

    { "$group": {
"_id": {
"evt": "$_id.evt",
"time": { "$slice": [ "$_id.val", 3,1 ] }
},
"count": { "$sum": "$value.count" }
}}

Что позволяет выбирать «третий» индексный элемент из массива, хотя это, конечно, все равно будет возвращать «массив» в качестве элемента, подобного этому:

{ "_id" : { "evt" : "click", "time" : [ "2" ] }, "count" : 2 }
{ "_id" : { "evt" : "click", "time" : [ "1" ] }, "count" : 5 }

Итак, прямо сейчас, если вы можете изменить исходный вывод mapReduce, сделайте это. Либо в форму, как показано здесь, либо просто работайте с изменениями исходного запроса, чтобы получить конечный результат, который вы хотите здесь. Изменение к рекомендованной форме, по крайней мере, позволит .aggregate() Команда для работы, как показано во втором примере здесь.

Если нет, то mapReduce в настоящее время остается единственным способом записи, как показано в «первом» примере.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector