2015-02-10 3 views
1

Для запроса во встроенные документы я хотел бы вернуть соответствующий элемент плюс заранее определенный набор элементов. Например, сВозможно ли вернуть выделенный подмножество массива встроенных документов из MongoDB

Say у меня есть коллекция, как показано ниже:

{_id: 1, 
data:[ 
    {who: 'Alice', score: 20}, 
    {who: 'Brad', score: 25}, 
    {who: 'Charlie', score: 30}, 
    {who: 'Dave', score: 40}, 
    {who: 'Elaine', score: 50}, 
    {who: 'Frank', score: 20} 

]}, 
{_id: 2, 
data:[ 
    {who: 'Alice', score: 30}, 
    {who: 'Brad', score: 50}, 
    {who: 'Charlie', score: 68}, 
    {who: 'Dave', score: 20}, 
    {who: 'Elaine', score: 50}, 
    {who: 'Frank', score: 20} 

]}, 
    ... 

Если мне нужно всегда возвращаться Алиса и Брэда, и каждый со счетом равен 50, я предпочитаю использовать

find({data.score: 50}, {'data.who': {'$in': ['Alice', 'Brad', '$']}}) 
or 
aggregate([{'$match': {data.score: 50}}, 
      {'$project': {'data': 1}}, 
      {'$unwind': '$data'}, 
      {'$match': {'data.who': {'$in': ['Alice', 'Brad', '$']}}}]) 

UNF К сожалению, ни одна из них не работает.

Что было бы правильным путем для его достижения или это возможно?

+0

вы хотите только data.who = Алиса, data.who = Брэд и data.score = 50 правильно? – Yogesh

ответ

0

Я думаю, как в моем понимании следующий запрос будет соответствовать вашим критериям

db.collectionName.aggregate({ 
    "$unwind": "$data" 
}, 
{ 
    "$match": { 
    "$or": [ 
     { 
      "data.score": 50 
     }, 
     { 
      "data.who": "Alice" 
     }, 
     { 
      "data.who": "Brad" 
     } 
    ] 
    } 
}, 
{ 
    "$project": { 
    "_id": 0, 
    "data": "$data" 
    } 
}).pretty() 
+0

На самом деле вам не нужно использовать два $ или оператора - нужно просто отлично "$ или": [{"data.score": 50}, {"data.who": "Alice"}, {"data .who ":" Brad "}] – marcinn

+0

@marcinn спасибо за указание этой проблемы сейчас я изменил запрос – Yogesh

1

Вы можете агрегировать результат, используя $redact стадии. Это устраняет необходимость этапа $unwind, который может оказаться довольно дорогостоящим в случае больших наборов данных.

  • Используйте оператор на $redact этапе, $$PRUNE подразделам документов , которые не соответствуют критериям, указанным в выражении $cond.

Код:

db.t.aggregate([ 
{$redact:{$cond:[{$or:[{$eq:[{$ifNull:["$who","Alice"]},"Alice"]}, 
         {$eq:[{$ifNull:["$who","Brad"]},"Brad"]}, 
         {$eq:[{$ifNull:["$score",50]},50]} 
         ]},"$$DESCEND","$$PRUNE"]}} 
]) 

Или вы можете сделать небольшое изменение в существующий код, как показано ниже:

  • Условие $match должен содержать все три условия для сохранить вспомогательный документ ,

  • Then $unwind.

  • Затем повторите одно и то же условие $match, чтобы выбрать неблокированные документы .

  • $group по _id закрепить выбранные суб документы данных для каждого _id.

Код:

db.t.aggregate([ 
{$match:{$or:[{"data.who":{$in:["Alice","Brad"]}}, 
       {"data.score":{$eq:50}}]}}, 
{$unwind:"$data"}, 
{$match:{$or:[{"data.who":{$in:["Alice","Brad"]}}, 
       {"data.score":{$eq:50}}]}}, 
{$group:{"_id":"$_id","data":{$push:"$data"}}} 
]) 

о/р:

{ 
     "_id" : 1, 
     "data" : [ 
       { 
         "who" : "Alice", 
         "score" : 20 
       }, 
       { 
         "who" : "Brad", 
         "score" : 25 
       }, 
       { 
         "who" : "Elaine", 
         "score" : 50 
       } 
     ] 
} 
{ 
     "_id" : 2, 
     "data" : [ 
       { 
         "who" : "Alice", 
         "score" : 30 
       }, 
       { 
         "who" : "Brad", 
         "score" : 50 
       }, 
       { 
         "who" : "Elaine", 
         "score" : 50 
       } 
     ] 
} 
+0

Вы протестировали, если' $ redact' выполняет намного лучше, чем '$ unind'?Оба должны будут исследовать каждый элемент массива, а также «большой эквивалент O», но мне интересно, есть ли у вас опыт использования как для одной и той же работы, так и с помощью «$ redact», что дает заметные улучшения? Правдоподобно, что '$ redact' лучше, чем' $ unind', учитывая, что '$ unwind' создает кучу дополнительных документов. – wdberkeley

+0

Я не тестировал их для работы в больших наборах данных. Но, по крайней мере, теоретически это не должно приводить к копиям документов, которые оказались бы дорогостоящими во время обработки трубопровода, что в случае размотки. Будет определенно пытаться измерить производительность и опубликовать обновление. – BatScream

+0

Спасибо за предложение $ redact. Поиграв с ним немного, он работает так, как ожидалось, за исключением того, что он может привести к слишком большому возвращенному документу и бросает, как $ unwind, на мое производство db. Может ли $ regex использоваться с $ redact? например {$ regex: ["$ v",/\ d {2} /]}. Я попытался, но это не сработало. По другому предложению он тоже работает, но мне нравится тот факт, что участвуют 2-футовые этапы одинакового критерия поиска. –

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