Запрос внутреннего размера массива в MongoDB - PullRequest
40 голосов
/ 17 июля 2011

Рассмотрим документ MongoDB в коллекции users:

{ username : 'Alex', tags: ['C#', 'Java', 'C++'] }

Есть ли способ получить длину массива tags со стороны сервера (без передачи тегов клиенту)?

Спасибо!

Ответы [ 6 ]

29 голосов
/ 16 декабря 2012

если имя пользователя 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 }
16 голосов
/ 08 апреля 2014

Теперь 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"}
         }
      }
   ]
)
16 голосов
/ 17 июля 2011

Я думаю, что было бы более эффективно вычислять количество тегов для каждого сохранения (как отдельное поле), используя $ inc , возможно, или с помощью задания по расписанию.

Вы также можете сделать это с картой / уменьшить ( канонический пример ), но это не то, что вы хотели бы.

Яне уверен, что возможно сделать именно то, что вы просите, но вы можете запросить все документы, которые соответствуют определенному размеру, с $ size ...

> db.collection.find({ tags : { $size: 3 }});

Это даст вамвсе документы с 3 тегами ...

10 голосов
/ 07 февраля 2014

xmm.dev ответ может быть упрощен: вместо промежуточного поля 'count' вы можете суммировать непосредственно в $ group:

db.test.aggregate(
  {$match: {username : "Alex"}}, 
  {$unwind: "$tags"},
  {$group: {_id: null, number: {$sum: 1 }}}
) 
9 голосов
/ 17 июля 2011

В настоящее время кажется, что единственный способ сделать это - использовать db.eval, но эта блокирует базу данных для других операций .

Самый эффективный способ - добавить дополнительное поле, в котором хранится длина массива, и поддержание его с помощью операций $ inc и $ push .

0 голосов
/ 06 ноября 2014

Я немного поработал, поскольку мне нужно было запросить размер массива и вернуть его, если он больше 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 размера в моем атрибуте, поэтому это решение сработало.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...