Подтвердить что ты не робот

Запрос размера внутреннего массива в MongoDB

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

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

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

Спасибо!

4b9b3361

Ответ 1

Теперь 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"}
         }
      }
   ]
)

Ответ 2

Если имя пользователя 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 }

Ответ 3

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

Вы также можете сделать это с помощью map/reduce (канонический пример), но это не похоже на то, что вы хотите.

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

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

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

Ответ 4

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

db.test.aggregate(
  {$match: {username : "Alex"}}, 
  {$unwind: "$tags"},
  {$group: {_id: null, number: {$sum: 1 }}}
) 

Ответ 5

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

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

Ответ 6

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