2014-02-12 3 views
0

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

{ 
    "_id" : ObjectId("52fac254f40ff600c10e56d4"), 
    "name" : "Mikey", 
    "list" : [ 1, 2, 3, 4, 5 ], 
    "people" : [ "Fred", "Barney", "Wilma", "Betty" ], 
    "status" : false, 
    "created" : ISODate("2014-02-12T00:37:40.534Z"), 
    "views" : 5 
} 

Теперь я знаю, что мы можем запросить для полей, которые соответствуют определенному типу с использованием оператора $type. Но я еще не наткнулся на способ $ project this в качестве значения поля. Так что, если мы смотрели на документ в «смотанной» форме вы увидите это:

{ 
    "_id" : ObjectId("52fac254f40ff600c10e56d4"), 
    "name" : 2, 
    "list" : 16, 
    "people" : 2 
    "status" : 8, 
    "created" : 9, 
    "views" : 16 
} 

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

{ 
    "_id" : ObjectId("52fac254f40ff600c10e56d4"), 
    "list" : [ 1, 2, 3, 4, 5 ], 
    "views" : 5 
} 

кто-нибудь есть подход справиться с этим.

ответ

2

Есть несколько проблем, которые делают это не практично:

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

Это, как говорится, есть немного эксцентричный способ использования Снизить карту эс получить аналогичные ответы, хотя и в Map-Reduce выхода стиля это не удивительный:

map = function() { 
    function isNumber(n) { 
     return !isNaN(parseFloat(n)) && isFinite(n); 
    } 

    var numerics = []; 
    for(var fn in this) { 
     if (isNumber(this[fn])) { 
      numerics.push({f: fn, v: this[fn]}); 
     } 
     if (Array.isArray(this[fn])) { 
      // example ... more complex logic needed 
      if(isNumber(this[fn][0])) { 
       numerics.push({f: fn, v: this[fn]}); 
      } 
     } 
    } 
    emit(this._id, { n: numerics }); 
}; 

reduce = function(key, values) { 
    return values; 
}; 

Это не полное, но результаты похожи на то, что вы хотели:

"_id" : ObjectId("52fac254f40ff600c10e56d4"), 
"value" : { 
     "n" : [ 
       { 
         "f" : "list", 
         "v" : [ 
           1, 
           2, 
           3, 
           4, 
           5 
         ] 
       }, 
       { 
         "f" : "views", 
         "v" : 5 
       } 
     ] 
} 

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

Конечно, это не так, как find или агрегация, но поскольку MongoDB не был разработан с учетом этого, это может потребоваться, если вам действительно нужна эта функциональность.

+0

Да. Это тоже мое мышление. Это произошло из-за другого вопроса, который в основном хотел отфильтровать поля таким образом. Может быть, оператор ** $ type ** в агрегации был бы хорош, в значительной степени по линии операторов даты, но я действительно не уверен в широкой полезности такой вещи. –

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