mongodb - получить подмножество массива - PullRequest
2 голосов
/ 17 июня 2011

то, что казалось простой задачей, стало для меня испытанием.

У меня следующая структура mongodb:

{
(...)
"services": {
    "TCP80": {
      "data": [{
          "status": 1,
          "delay": 3.87,
          "ts": 1308056460
        },{
          "status": 1,
          "delay": 2.83,
          "ts": 1308058080
        },{
          "status": 1,
          "delay": 5.77,
          "ts": 1308060720
        }]
    }
}}

Теперь следующий запрос возвращает весь документ:

{ 'services.TCP80.data.ts':{$gt:1308067020} }

Интересно - могу ли я получить только те записи массива "data", которые соответствуют критериям $ gt (вид сокращенного документа)?

Я рассматривал MapReduce, но не смог найти ни одного примера о том, как передать внешние аргументы (timestamp) в функцию Map (). (Эта функция была добавлена ​​в 1.1.4 https://jira.mongodb.org/browse/SERVER-401)

Кроме того, всегда есть альтернатива написанию функции StorageJs, но, поскольку мы говорим о больших объемах данных, здесь нельзя допускать блокировки db.

Скорее всего, мне придется переделать структуру до уровня 1-го уровня, например:

{
   status:1,delay:3.87,ts:138056460,service:TCP80
},{
   status:1,delay:2.83,ts:1308058080,service:TCP80
},{
   status:1,delay:5.77,ts:1308060720,service:TCP80
}

, но БД резко возрастет, поскольку «служба» - это только одна из многих опций, которые будут добавлять каждый документ.

пожалуйста, совет!

заранее спасибо

Ответы [ 4 ]

2 голосов
/ 04 апреля 2012

В версии 2.1 с платформой агрегации вы теперь можете сделать это:

1: db.test.aggregate(
2:   {$match : {}},
3:   {$unwind: "$services.TCP80.data"},
4:   {$match: {"services.TCP80.data.ts": {$gte: 1308060720}}}
5: );

Вы можете использовать пользовательские критерии в строке 2 для фильтрации родительских документов.Если вы не хотите их фильтровать, просто не указывайте строку 2.

1 голос
/ 17 июня 2011

В настоящее время это не поддерживается.По умолчанию вы всегда будете получать весь документ / массив, если вы не используете ограничения полей или оператор $ slice.В настоящее время эти инструменты не позволяют фильтровать элементы массива на основе критериев поиска.

Вы должны посмотреть этот запрос, чтобы узнать, как это сделать: https://jira.mongodb.org/browse/SERVER-828

0 голосов
/ 27 июля 2011

Фади, что касается "хранения встроенных документов отдельно" - группа должна справиться с этим без проблем

function getServiceData(collection, criteria) {

    var res=db[collection].group({
        cond: criteria,
        initial: {vals:[],globalVar:0},
        reduce: function(doc, out) {
            if (out.globalVar%2==0)
                out.vals.push({doc.whatever.kind.and.depth);
                out.globalVar++;
        },
        finalize: function(out) {
            if (vals.length==0)
                out.vals='sorry, no data';
            return out.vals;
        }
    });

    return res[0];
};
0 голосов
/ 22 июля 2011

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

Мне нужно было получить / получить подмножество вложенных документов по идентификатору.Вот как я это сделал, используя Map / Reduce:

db.parent.mapReduce(
  function(parent_id, child_ids){
    if(this._id == parent_id) 
      emit(this._id, {children: this.children, ids: child_ids})
  }, 
  function(key, values){
    var toReturn = [];

    values[0].children.forEach(function(child){
      if(values[0].ids.indexOf(product._id.toString()) != -1)
        toReturn.push(child);
    });
    return {children: toReturn};
  }, 
  { 
     mapparams: [
       "4d93b112c68c993eae000001", //example parent id
       ["4d97963ec68c99528d000007", "4debbfd5c68c991bba000014"] //example embedded children ids
     ]
  }
).find()

Я абстрагировал имя своей коллекции до «parent», а встроенные документы - до «children».Я передаю два параметра: идентификатор родительского документа и массив идентификаторов встроенного документа, которые я хочу получить от родителя.Эти параметры передаются в качестве третьего параметра в функцию mapReduce.

В функции карты я нахожу родительский документ в коллекции (который, я уверен, использует индекс _id) и выдает его идентификатор и дочерние элементы.к функции сокращения.

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

В функции сокращения я также предполагаю, что только один документ выдан, поскольку я ищу по идентификатору.Если вы ожидаете, что совпадет более одного parent_id, вам придется циклически перебирать массив values в функции Reduce.

Надеюсь, это кому-нибудь поможет, поскольку я везде гуглил без результатов.Надеюсь, скоро мы увидим встроенную функцию MongoDB, но до тех пор я должен ее использовать.

...