@livemirsi

MongoDB (сравнение массивов, агрегация, большие количество данных)?

Добрый день. Обдумываю структура проекта. На входе имеем базу mongodb (рассмотрел бы и другие бд, но монга очень понравилась). Вообщем в коллекции есть документы, покажу 3 поля, ибо остальные просто доп.инфа, не для расчетов.
{
id: ....
name: ......
properties: [1, 2, 4, 5, ....] - до 100 значений в массиве, значения цифры.
}
Буду брать с базы нужные мне записи по свойствами, которые хранятся в массив в поле:
db.collect.find({"properties": {$all:[1,3,5, 100]}})
Вроде всё здорово, могу брать маленькими пачками, скажем по 50 документов, отдавать их клиенту.
Но есть загвоздка, мне нужно не просто получить список документов по свойствам. А провести еще аналитику массива свойств у всех документов.
Думаю использовать два запроса к бд:
1. db.collect.find({"properties": {$all:[1,3,5, 100]}}) - получаю нужную мне пачку доков, по их свойствам. Ограничу выбору в 50 документов.
2. Тут вся загвоздка, мне на выходе надо получить оценку всех массивов у документов, а именно узнать какие значения сколько раз встречались в различных документах, по типу
1 - встречалось в поле properties 350 раз
2 - встречалось в поле properties 100 раз
Пока не понимаю, как сделать такую операцию, копаю в строну агрегации, но не уверен что смогу добиться нужного мне результата.
Есть еще момент, 2 запрос, он не должен иметь ограничений в выборки, то есть если отправим
db.collect.find({"properties": {$all:[1]}}) можем получить 10-20 000 а можем и больше документов в которых нужно узнать какие значения из поля properties дублируются во всех документах и сколько ра.
Посоветуйте как можно решить такую проблему, стоит ли копать дальше в агрегацию или подумать еще над чем то?

UPD:
Задачу решил, оказалось всё просто:
db.collect.aggregate(
{$match: {parameters: {$all: [4,2]}}},
{$unwind:{path:"$parameters"}}, 
{$project:{parameters: true, count: {$add: [1]}}}, 
{$group: {_id: "$parameters", dublicate:{$sum:"$count" } }}
)

match - делают нужную выбору документов
unwind - разворачивает массив параметров
project: сохраняем только поле параметров, добавляем ему поле count, что бы посчитать было проще
group - группируем и складываем count
В итоге, имеем количество повторений элементов массивов в нужно нам выборки.
Правда в нее попадают и элементы, по которым изначально выборку ограничивали, но это не страшно, их убрать можно в обработке самого приложения.

Не уверен в производительности данного решения, буду тестить.
  • Вопрос задан
  • 2655 просмотров
Пригласить эксперта
Ответы на вопрос 2
@lega
1 - встречалось в поле properties 350 раз
2 - встречалось в поле properties 100 раз

Для этого можно держать кеш: {_id: 1, count: 350}

db.collect.find({"properties": {$all:[1]}})
Когда элемент один, лучше так:
db.collect.find({"properties": 1})
Ответ написан
pomeo
@pomeo
Aggregation вам в любом случае немножко задачу упростит.
Например у вас 100000 документов с [1,2,3], вы делаете match: {$all:[1,2,3]}, дальше group по 1 например. И у вас остаётся один документ. Вот как посчитать потом оптимизированно, что документ один например с ходу не вижу. Можно конечно пройтись встроенным в монгу forEach по выдачем после group и сделать db.collect.count, но это не красиво, хотя задачу решает.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы