Существует два способа сделать это, используя конвейер агрегации. Функции сокращения карты не требуются.
Первый подход основан на предположении, что документы в категории main
всегда будут вставлены перед другими документами для того же uid
и всегда будет иметь id
меньше, чем другие документы, имеющие один и тот же uid
. Если этот вопрос будет учтен во время ввода документа, мы можем сортировать его на поле id
и, кроме того, индексировать его.
Sort
на основе поля индекса.
Group
от uid
раздел. Таким образом, первая запись для каждой группы будет записи категории main
.
Match
только те группы, у которых есть запись категории main
.
Unwind
все записи в каждой группе и применяют предмет первой записи ко всем записям в каждой группе.
Кодекс:
collection.aggregate([
{$sort:{"id":1}},
{$group:{"_id":"$uid",
"cat":{$first:"$cat"},
"subject":{$first:"$subject"},
"record":{$push:"$$ROOT"}}},
{$match:{"cat":"main"}},
{$unwind:"$record"},
{$project:{"_id":0,
"id":"$record.id",
"uid":"$_id",
"cat":"$record.cat",
"subject":"$subject"}}
],function(err,resp){
console.log(resp);
})
Второй подход скотина реализация простого примера вы указали, что может оказаться меньшим исполнителем.
Для определения записи категории main
для каждой группы требуется дополнительный оператор проекции. Мы сортируем на основе этого прогнозируемого поля. Оставшаяся логика такая же.
db.collection.aggregate([
{$project:{"_id":0,
"id":1,"uid":1,"cat":1,"subject":1,
"isMainRecord":{$cond:[{$eq:["$cat","main"]},0,1]}}},
{$sort:{"isMainRecord":1}},
{$group:{"_id":"$uid",
"cat":{$first:"$cat"},"subject":{$first:"$subject"},
"record":{$push:"$$ROOT"}}},
{$match:{"cat":"main"}},
{$unwind:"$record"},
{$project:{"_id":0,"id":"$record.id",
"uid":"$_id","cat":"$record.cat","subject":"$subject"}}
],{allowDiskUse:true},function(err,resp){
console.log(resp);
})
благодарит за ваш ответ, я смог построить запрос, выполнив первый пример, но с тестовой записью в 1 миллион, когда я выполняю поиск с большим количеством атрибутов, таких как диапазон дат в соответствии с лимитом 25, результат получается почти 4-5 секунд, я думаю, это потому, что сначала отсортированы все записи, а затем группа применяется ко всем записям за 1 миллион? я прав ? все равно оптимизировать это? – Arian
Да. Вы можете индексировать поле id в порядке возрастания и удалить первую операцию сортировки. – BatScream