2013-04-20 1 views
0

Я использую динамический конструктор форм для хранения значений в mongo. Значение полей определяется во время выполнения.Проецирование sub-запроса в mongo

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

Вот пример 2 записей в коллекции

{ 
"_id": { 
    "$oid": "511ff0a8521e66d41b0d35d6" 
}, 
"FormID": { 
    "$uuid": "413ba627-94bf-0ca7-49b3-9ca2a1a3e9b5" 
}, 
"ResultID": { 
    "$uuid": "45f455ae-8486-aaa9-b97a-e480bfdf3db4" 
}, 
"FieldValues": [ 
    { 
     "FieldID": "first name", 
     "FieldValue": "John" 
    }, 
    { 
     "FieldID": "last name", 
     "FieldValue": "smith" 
    }, 
    { 
     "FieldID": "school", 
     "FieldValue": "high school" 
    }, 
    { 
     "FieldID": "favorite subject", 
     "FieldValue": "math" 
    }, 

] 
}, 

{ 
"_id": { 
    "$oid": "511ff0a8521e66d41b0d35d7" 
}, 
"FormID": { 
    "$uuid": "413ba627-94bf-0ca7-49b3-9ca2a1a3e9b5" 
}, 
"ResultID": { 
    "$uuid": "45f455ae-8486-aaa9-b97a-e480bfdf3db5" 
}, 
"FieldValues": [ 
    { 
     "FieldID": "first name", 
     "FieldValue": "sarah" 
    }, 
    { 
     "FieldID": "last name", 
     "FieldValue": "smith" 
    }, 
    { 
     "FieldID": "school", 
     "FieldValue": "high school" 
    }, 
    { 
     "FieldID": "favorite subject", 
     "FieldValue": "english" 
    }, 

] 
}, 

Скажем, я хотел бы проецировать Результат Id, Имя, Фамилия

В SQL - я бы уже FieldValues ​​определены в его собственную таблицу, и я бы выполнил дополнительный запрос в значениях поля, где ResultId = (идентификатор результата родителя) и FieldID = «first name», затем другой подзапрос на «фамилию» и т. д., чтобы сгладить результаты.

Я пытался выяснить, как это сделать с монго. Мне удалось найти оператор $ slice, но это позволяет вам получить последовательный набор элементов массива.

Причина, по которой я не хочу получить весь документ, заключается в том, что в некоторых случаях мои клиенты определили более 400 полей для отслеживания. Уничтожение всего этого на 200 строк может означать 100 МБ данных, передаваемых по сети и десериализованных (медленных).

Любые советы/предложения будут оценены

+0

Любопытно, почему вы отметили вопрос с помощью mapreduce? –

+0

Я думаю, что есть способ сделать это в mapreduce, чтобы люди, которые следовали за этим тегом, могли бы помочь. Но я знал, что структура агрегации также возможна. – apexdodge

ответ

2

Вы можете создать соответствующий рамочную агрегацию синтаксис для возврата именно то, что вы хотите. Он может быть не достаточно быстрым, но он вернет точный формат, который вы хотите, не вытащив полный документ. Чтобы сделать это быстро, я предполагаю, что вы избегаете запускать его по всей коллекции, если первый этап конвейера должен быть {$match}, который выбирает только соответствующее подмножество документов (и эти критерии должны быть проиндексированы).

Используя следующие этапы трубопровода над вашими двумя документами образца для полей first name и last name, вы возвращаете только _id и эти поля. Для набора заданных идентификаторов полей вы можете сгенерировать этот конвейер программно.

unwind = { "$unwind" : "$FieldValues" }; 

match = { "$match" : { 
     "FieldValues.FieldID" : { 
      "$in" : [ 
       "first name", 
       "last name" 
      ] 
     } 
    } 
}; 

proj = { "$project" : { 
     "first name" : { 
      "$cond" : [ 
       { 
        "$eq" : [ 
         "first name", 
         "$FieldValues.FieldID" 
        ] 
       }, 
       "$FieldValues.FieldValue", 
       " skip" 
      ] 
     }, 
     "last name" : { 
      "$cond" : [ 
       { 
        "$eq" : [ 
         "last name", 
         "$FieldValues.FieldID" 
        ] 
       }, 
       "$FieldValues.FieldValue", 
       " skip" 
      ] 
     } 
    } 
}; 

group = { "$group" : { 
     "_id" : "$_id", 
     "first name" : { 
      "$max" : "$first name" 
     }, 
     "last name" : { 
      "$max" : "$last name" 
     } 
    } 
}; 

db.project.aggregate(unwind, match, proj, group) 
{ 
    "result" : [ 
     { 
      "_id" : ObjectId("511ff0a8521e66d41b0d35d7"), 
      "first name" : "sarah", 
      "last name" : "smith" 
     }, 
     { 
      "_id" : ObjectId("511ff0a8521e66d41b0d35d6"), 
      "first name" : "John", 
      "last name" : "smith" 
     } 
    ], 
    "ok" : 1 
} 
+0

Я написал общий программный способ создания этого конвейера в своем блоге: http://www.kamsky.org/1/post/2013/04/using-aggregation-framework- к-RESHAPE-schema.html –

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

  • Нет связанных вопросов^_^