2015-06-16 2 views
2

Я пытаюсь написать сводный запрос, используя $ unwind независимо от того, является ли элемент массивом или нет. Я знаю, что $unwind не работает ни в каких элементах массива, но мне интересно, есть ли способ заставить его работать, например, преобразовать этот элемент в массив.mongodb aggregate unind array и no array

У меня есть коллекции, как это:

{ 

    {"x" : 1, "y" : {"c" : 2, "i" : 3}}, 
    {"x" : 1, "y" : [{"c" : 4, "i" : 5}, {"c" : 6, "i" : 7}]} 

} 

Перед тем, как $unwind я думаю, что мне нужно что-то вроде этого:

{ 

    {"x" : 1, "y" : [{"c" : 2, "i" : 3}]}, 
    {"x" : 1, "y" : [{"c" : 4, "i" : 5}, {"c" : 6, "i" : 7}]} 
} 

До сих пор в $project этапе я могу проверить, если элемент массива или нет , но я не знаю, как использовать эту информацию для создания массива или нет. Я знаю, что могу использовать $push для создания массива, но как оставить нетронутые элементы массивов и просто $push нет элементов массива?

Я попытался это:

{$group : {"_id" : "$x", "myArray" : {$push : {$cond : {if : "$isArray", then : "$y", else : ["$y"]}}}}} 

С кодом выше я попытался иметь все элементы в том же уровне, но не работает, так как ["$y"] возвращается точно, что (["$y"]), нет оценки, просто массив со строкой в Это.

Я не хочу, чтобы $ разматывать пустой массив, я хочу преобразовать элемент non array в элемент массива, чтобы я мог развернуть.

любая помощь будет оценена по достоинству.

+0

Я не понимаю ваши комментарии об изменении образца в одно и то же. Первый образец содержит элементы массива и не-массива для «y», второй - то, что я сказал, со всеми «y» элементами в виде массивов. О возможном дублировании, я думаю, что это не мое дело, так как у меня нет и пустого массива. У меня есть элемент non array, который я хочу включить, и массив, чтобы я мог развернуть. –

+0

Я согласен, что это не очень хорошая идея, но я не писал эту коллекцию, и изменить ее сейчас не вариант. –

ответ

4

Это в основном делает то, что вы хотите с некоторой помощью $cond и $ifNull:

db.collection.aggregate([ 
    { "$project": { 
     "x": 1, 
     "y": { 
      "$cond": [ 
       { "$ifNull": [ "$y.0", null] }, 
       "$y", 
       { "$map": { 
        "input": ["A"], 
        "as": "el", 
        "in": "$y" 
       }} 
      ] 
     } 
    }} 
]) 

Так что те первые условия работы из «является элементом массива» по существу проверки на наличие «первой index "элемента массива. Если условие истинно, то используется существующий элемент, т. Е. Массив.

Если это не так, элемент «преобразуется» в массив через функцию $map и отдельный элемент массива «фиктивный».

Выход только то, что вы хотите:

{ 
    "_id" : ObjectId("557f9d9d655c7c61fdcb7909"), 
    "x" : 1, 
    "y" : [ 
      { 
        "c" : 2, 
        "i" : 3 
      } 
    ] 
} 
{ 
    "_id" : ObjectId("557f9d9d655c7c61fdcb790a"), 
    "x" : 1, 
    "y" : [ 
      { 
        "c" : 4, 
        "i" : 5 
      }, 
      { 
        "c" : 6, 
        "i" : 7 
      } 
    ] 
} 

Я бы еще посоветовать, где это возможно, что вы изменяете документы на самом деле содержат элемент массива в вашей коллекции, а не работать это в трубопровод. Что-то вроде этого:

db.collection.find({ "y.0": { "$exists": false } }).forEach(function(doc) { 
    db.collection.update(
     { "_id": doc._id }, 
     { "$set": { "y": [doc.y] } } 
    ) 
}) 
+0

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

+0

@RaulMartinez У вас может еще не быть требуемой привилегии «отменить» ответ, но вы можете [принять] (http: // stackoverflow.com/help/принято-ответ) –