2015-09-24 4 views
3

Возможно ли получить позицию элемента массива, соответствующего запросу?Извлечь позицию в массиве в mongodb

К примеру, у меня есть коллекция с документами, как это:

{"_id":ObjectId("560122469431950bf55cb095"), "otherIds": [100, 103, 108, 104]} 

И я хотел бы, чтобы получить результат запроса, как это для otherId-> 108:

{"_id":ObjectId("560122469431950bf55cb095"),"position":3} 

Является ли это можно получить что-то вроде этого? Заранее спасибо!

ответ

1

Ну вы всегда можете запустить mapReduce для этого и соответствует индексу массива через .indexOf():

db.collection.mapReduce(
    function() { 
     emit(this._id,{ "position": this.otherIds.indexOf(108) }); 
    }, 
    function() {}, 
    { 
     "out": { "inline": 1 }, 
     "query": { "otherIds": 108 } 
    } 
) 

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

db.collection.mapReduce(
    function() { 
     emit(this._id,{ 
      "positions": this.otherIds.map(function(el,idx) { 
       return (el == 108) ? idx : -1; 
      }).filter(function(el) { 
       return el != -1; 
      }) 
     }); 
    }, 
    function() {}, 
    { 
     "out": { "inline": 1 }, 
     "query": { "otherIds": 108 } 
    } 
) 

Но, конечно, индексы массива начинаются с 0, поэтому, если вы ожидаете, что результат будет 3, тогда вы n всегда добавляйте 1 в соответствующее положение индекса.

Разумеется, вы просто просто возвращаете массив в ответе на запрос и просто соглашаетесь с позицией (-ами) согласованного элемента в клиентском коде и, вероятно, лучше всего обрабатывать этот путь, если у вас нет особо больших массивов ,

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

Также можно утверждать, что другие операторы, такие как $map, и предстоящий $filter (также в ветви dev) должны иметь аналогичную возможность, как системную переменную, доступную в этих командах, таких как их JavaScript и другие эквиваленты языков. Тогда что-то вроде $$IDX (простирания от других системных переменных, как $$ROOT) доступна, то вы могли бы сделать это под .aggregate():

db.collection.aggregate([ 
    { "$match": { "otherIds": 108 } }, 
    { "$project": { 
     "position": { 
      "$filter": { 
       "input": { 
        "$map": { 
         "input": "$otherIds", 
         "as": "el", 
         "in": { 
          "$cond": [ 
           { "$eq": [ "$$el", 108 ] }, 
           "$$IDX", 
           -1 
          ] 
         } 
        } 
       }, 
       "as": "el", 
       "cond": { "$ne": ["$$el", -1] } 
      } 
     } 
    }} 
]) 

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

+0

Большое спасибо Blakes Seven, я не думаю, что выполнение сокращения карты - лучший подход для моего случая, я попытался бы сохранить данные в другом расположении. – hiamex

+0

@hiamex Вероятно, было бы лучше, если бы вы задали вопрос, который вместо этого объяснил, почему вам нужно это поведение совпадающего индекса. Как указано, в целом, вероятно, лучше всего просто выработать позицию в клиентском коде, если только ваши массивы не являются особенно большими, и у вас есть что-то, что можно получить от других действий. –

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