Рассмотрим документ MongoDB в коллекции users
:
{ username : 'Alex', tags: ['C#', 'Java', 'C++'] }
Есть ли способ получить длину массива tags
со стороны сервера (без передачи тегов клиенту)?
Спасибо!
Рассмотрим документ MongoDB в коллекции users
:
{ username : 'Alex', tags: ['C#', 'Java', 'C++'] }
Есть ли способ получить длину массива tags
со стороны сервера (без передачи тегов клиенту)?
Спасибо!
Теперь MongoDB (версия 2.6) поддерживает $size
операцию в агрегации.
Из документации:
{ <field>: { $size: <array> } }
То, что вы хотите, может быть выполнено следующим образом:
db.users.aggregate(
[
{
$group: {
_id: "$username",
tags_count: {$first: {$size: "$tags" }}
}
}
]
)
или
db.users.aggregate(
[
{
$project: {
tags_count: {$size: "$tags"}
}
}
]
)
Если имя пользователя Alex уникально, вы можете использовать следующий код:
db.test.insert({username:"Alex", tags: ['C#', 'Java', 'C++'] });
db.test.aggregate(
{$match: {username : "Alex"}},
{$unwind: "$tags"},
{$project: {count:{$add:1}}},
{$group: {_id: null, number: {$sum: "$count" }}}
);
{ "result" : [ { "_id" : null, "number" : 3 } ], "ok" : 1 }
Я думаю, что было бы более эффективно вычислять количество тегов для каждого сохранения (как отдельное поле), используя $inc, возможно, или через работу по расписанию.
Вы также можете сделать это с помощью map/reduce (канонический пример), но это не похоже на то, что вы хотите.
Я не уверен, что можно сделать именно то, что вы просите, но вы можете запросить все документы, соответствующие определенному размеру, с помощью $size...
> db.collection.find({ tags : { $size: 3 }});
Это даст вам все документы с 3 тегами...
xmm.dev ответ может быть упрощен: вместо того, чтобы иметь интерм-поле 'count', вы можете суммировать непосредственно в $group:
db.test.aggregate(
{$match: {username : "Alex"}},
{$unwind: "$tags"},
{$group: {_id: null, number: {$sum: 1 }}}
)
В настоящее время единственный способ сделать это, кажется, использует db.eval
, но этот блокирует базу данных для других операций.
Наиболее эффективным с точки зрения скорости способом было бы добавление дополнительного поля, которое хранит длину массива и поддерживая его $inc и $push.
Я сделал небольшую работу, так как мне нужно было запросить размер массива и вернуть его, если оно больше 0, но может быть чем угодно от 1-3.
Вот мое решение:
db.test.find($or : [{$field : { $exists : true, $size : 1}},
{$field : { $exists : true, $size : 2}},
{$field : { $exists : true, $size : 3}}, ])
Это в основном возвращает документ, если атрибут существует, а размер 1, 2 или 3. Пользователь может добавлять дополнительные инструкции и увеличивать, если они ищут определенный размер или диапазон. Я знаю, что он не идеален, но он работал и был относительно быстрым. У меня было только 1-3 размера в моем атрибуте, поэтому это решение сработало.