5

Я только начал изучать MongoDB и не могу найти решение для моей проблемы.Проекция многомерного массива MongoDB

Получил этот документ:

> db.test.insert({"name" : "Anika", "arr" : [ [11, 22],[33,44] ] }) 

Пожалуйста, обратите внимание на поле «аранжировка», который представляет собой многомерный массив.

Теперь я ищу запрос, который возвращает только значение arr [0] [1], которое равно 22. Я пытался добиться этого, используя $ slice, однако я не знаю, как обращаться ко второму с этим.

> db.test.find({},{_id:0,"arr":{$slice: [0,1]}}) 
{ "name" : "ha", "arr" : [ [ 11, 22 ] ] } 

Я также попытался

> db.test.find({},{_id:0,"arr":{$slice: [0,1][1,1]}}) 
{ "name" : "ha", "arr" : [ [ 11, 22 ] ] } 

Нужный результат будет либо

22 

или

{"arr":[[22]]} 

Спасибо


EDIT:

После прочтения комментариев я думаю, что я упростил пример данных слишком много, и я должен предоставить более подробную информацию:

  1. Есть много других документов в коллекция, подобная той, что Я предоставил. Но все они имеют одинаковую структуру.
  2. Есть несколько элементов массива, чем просто два
  3. В реальном мире массив содержит очень длинные тексты (500кб-1MB), , поэтому очень экспансивный передавать целые данные клиенту.
  4. Перед агрегацией я сделаю запрос по полю «имя». Просто пропустил это в примере для простоты.
  5. Целевые показатели являются переменными, так что иногда мне нужно знать значение обр [0] [1], в следующий раз, это обры [1] [4]

примера данные, :

> db.test.insert({"name" : "Olivia", "arr" : [ [11, 22, 33, 44],[55,66,77,88],[99] ] }) 
> db.test.insert({"name" : "Walter", "arr" : [ [11], [22, 33, 44],[55,66,77,88],[99] ] }) 
> db.test.insert({"name" : "Astrid", "arr" : [ [11, 22, 33, 44],[55,66],[77,88],[99] ] }) 
> db.test.insert({"name" : "Peter", "arr" : [ [11, 22, 33, 44],[55,66,77,88],[99] ] }) 

пример запроса:

> db.test.find({name:"Olivia"},{"arr:"...}) 

ответ

2

Вы можете использовать структуру агрегации:

db.test.aggregate([ 
    { $unwind: '$arr' }, 
    { $limit: 1 }, 
    { $project: { _id: 0, arr: 1 } }, 
    { $unwind: '$arr' }, 
    { $skip: 1 }, 
    { $limit: 1 } 
]) 

Возвращает:

{ "arr": 22 } 

Edit: Оригинальный плакат изменил свое решение, чтобы удовлетворить его потребности и придумал следующее:

db.test.aggregate([ 
    { $match: { name:"Olivia" } }, 
    { $project: { _id: 0,arr: 1 } }, 
    { $unwind: '$arr' }, 
    { $skip: 1 }, 
    { $limit:1 }, 
    { $unwind: "$arr" }, 
    { $skip: 2 }, 
    { $limit: 1 } 
]) 

Этот запрос приведет к { arr: 77 } с учетом расширенных данных, предоставленных OP. Обратите внимание, что $ skip и $ limit необходимы для выбора правильных элементов в иерархии массивов.

+0

Это не может работать ни на одном, кроме одного документа. Конечно, '$ skip' и' $ limit' "имитируют" индексированные позиции, но после того, как вы 'разматываете' на нескольких сборных документах, это становится неуместным. –

+0

Он будет работать, если желаемый выход ** равен ** для одного документа. Всегда можно получить только один желаемый документ, используя '$ match'. –

+0

Это никогда не будет реалистично. Речь идет о том, чтобы дать людям «реальные» примеры, которые они действительно могут использовать. Отдельные случаи документов лучше кодируются в клиенте, как я сказал в своем ответе. –

0

$slice форма, которую вы просите, не делает многомерные массивы. Каждый массив рассматривается индивидуально и поэтому не поддерживается таким образом текущим $slice.

Как таковой, он на самом деле сделано намного короче индексированных «первых» и «последних» значений, чем было предложено использовать .aggregate(), и в настоящее время:

db.test.aggregate([ 
    { "$unwind": "$arr" }, 
    { "$group": { 
     "_id": "$_id", 
     "arr": { "$first": "$arr" } 
    }}, 
    { "$unwind": "$arr" }, 
    { "$group": { 
     "_id": "$_id", 
     "arr": { "$last": "$arr" } 
    }} 
]) 

Но в будущих версиях MongoDB (в настоящее время работает в развития отрасли 3,18 в письменной форме) у вас есть $arrayElemAt как оператор для структуры агрегации, которая работает следующим образом:

db.test.aggregate([ 
    { "$project": { 
     "arr": { 
      "$arrayElemAt": [ 
       { "$arrayElemAt": [ "$arr", 0 ] }, 
       1 
      ] 
     } 
    }} 
]) 

И в основном приходят к тому же { "arr": 22 } результате, несмотря на то, будущая доступная форма работает довольно гибко по значениям индекса массива, а не первой и последней.

+0

Полезно знать о '$ arrayElemAt'! Спасибо, что поделился. Однако у меня вопрос о вашем использовании операторов агрегации. Разве «$ group» дороже по сравнению с «$ limit» в моем примере? –

+0

Кроме того, если вы не знаете количество элементов в массиве, вы, вероятно, не сможете использовать '$ first' и' $ last'. Поэтому использование '$ limit' выглядит более универсальным для меня. –

+1

@DmytroShevchenko Nope. Более сложные стадии агрегации - более дорогие. ПОЛНАЯ ОСТАНОВКА. Чем меньше тем лучше. Конечно, новые операторы (когда они становятся доступными) означают один этап, что является лучшим результатом. Честно говоря, если это полная сложность того, что вы просите, то структура агрегации не является «в настоящее время» ответом. Сделайте это в клиентском коде вместо этого, что намного эффективнее. –

Смежные вопросы