Запрос расширенного подсчета MongoDB в зависимости от содержимого документа

У меня проблема с расширенным запросом подсчета с MongoDB.

Я пытаюсь подсчитать объект внутри поля документа, но только если предыдущий элемент, соответствующий запросу, существует и старше< /strong> в массиве.

Позволь мне объяснить....

У меня есть контейнерный документ, который выглядит так:

{
 "_id" : ...,
 [...]
 "objects" : [ ]
}

Внутри полей объектов:
у меня есть документ объекта, который выглядит так:

[
  {
    "_id" : ...,
    "name" : "foo",
    "properties" = [ ],
    "time" = 000000042
  }

  {
    "_id" : ...,
    "name" : "bar",
    "properties" = [ ],
    "time" = 000000424
  }

  {
    "_id" : ...,
    "name" : "baz",
    "properties" = [ ],
    "time" = 000004242
  }

Сейчас я подсчитываю, сколько содержит документов-контейнеров:
количество контейнеров с объектом 1 (foo),
количество контейнеров с объектами 1 и 2 (foo и bar),
количество контейнеров с объектами 1, 2 и 3 (фу, бар, баз)

Но теперь я хочу считать foo и bar, только если bar старше, чем foo (используя поле времени)...
< strong>количество
контейнеров с объектом 1 (foo),
количество контейнеров с объектами 1 и 2 (foo и bar), И foo.time ‹ bar.time
количество контейнеров с объектами 1, 2 и 3 (foo, bar , baz) И foo.time ‹ bar.time ‹ baz.time

Проблема в том, что поле времени должно меняться для каждого контейнера. Другими словами: как я могу использовать динамический запрос для каждого документа

вот пример кода:

foreach ($COUNTER[ARRAY_FIELDS_NAME_TO_COUNT] as $key => $value)
{
// Build the query (Name & properties)
$match[$key] = array('$elemMatch' => array('name' => $value['name']));
foreach ($value['properties'] as $propertyName => $propertyValue)
  $match[$key]['$elemMatch']["properties.$propertyName"] = $propertyValue;

// Time checking
if ($key > 0)
{
  //FIXME with a... dynamics query searching inside current doc??
  //           or   a special var set to the previous object matched...  or MapReduce..
}


// Make the query
$query = array('objects' => array('$all' => $match));

$result[$key]['count'] = $db->person->count($query);
}

Я новичок в MongoDB, и я действительно не знаю, как лучше всего сделать это эффективно!

С уважением!


person B0ltz    schedule 05.10.2012    source источник
comment
ты используешь 2.2? и достаточно ли мало этих условий? являются ли foo ‹ bar и foo‹bar‹baz фактическим запросом, который вы должны сделать, или есть намного больше условий?   -  person Asya Kamsky    schedule 08.10.2012
comment
Привет, да, я использую 2.2.0, мне нужно сопоставить около 5 или немного больше содержащихся объектов, таких как foo и bar.   -  person B0ltz    schedule 08.10.2012


Ответы (1)


Вот как вы можете сделать это с помощью Aggregation Framework в оболочке (javascript).

Обратите внимание, что я разделил это на несколько строк для удобства чтения, фактический запрос — последняя строка. Я использовал foo bar и baz, но, конечно, вы хотите приспособиться к чему-то более подходящему.

match = { "$match" : { "objects.name" : "foo" } };
unwind = { "$unwind" : "$objects" };
projectDates = {"$project" : {
        "_id" : 1,
        "objects" : 1,
        "fooDate" : {
            "$cond" : [
                {
                    "$eq" : [
                        "$objects.name",
                        "foo"
                    ]
                },
                "$objects.time",
                0
            ]
        },
        "barDate" : {
            "$cond" : [
                {
                    "$eq" : [
                        "$objects.name",
                        "bar"
                    ]
                },
                "$objects.time",
                0
            ]
        },
        "bazDate" : {
            "$cond" : [
                {
                    "$eq" : [
                        "$objects.name",
                        "baz"
                    ]
                },
                "$objects.time",
                0
            ]
        }
    }
};
group = {"$group" : {
        "_id" : "$_id",
        "objects" : {
            "$push" : "$objects"
        },
        "maxFooDate" : {
            "$max" : "$fooDate"
        },
        "maxBarDate" : {
            "$max" : "$barDate"
        },
        "maxBazDate" : {
            "$max" : "$bazDate"
        }
    }
};
projectCount = {"$project" : {
        "_id" : 1,
        "foos" : {
            "$add" : [
                1,
                0
            ]
        },
        "foosAndBars" : {
            "$cond" : [
                {
                    "$lt" : [
                        "$maxFooDate",
                        "$maxBarDate"
                    ]
                },
                1,
                0
            ]
        },
        "foosBarsAndBazs" : {
            "$cond" : [
                {
                    "$and" : [
                        {
                            "$lt" : [
                                "$maxBarDate",
                                "$maxBazDate"
                            ]
                        },
                        {
                            "$lt" : [
                                "$maxFooDate",
                                "$maxBarDate"
                            ]
                        }
                    ]
                },
                1,
                0
            ]
        }
    }
};
countFoos = {"$group" : {
        "_id" : "FoosBarsBazs",
        "Foos" : {
            "$sum" : "$foos"
        },
        "FBs" : {
            "$sum" : "$foosAndBars"
        },
        "FBBs" : {
            "$sum" : "$foosBarsAndBazs"
        }
    }
};


db.collection.aggregate([match, unwind, projectDates, projectCount, countFoos]).result
person Asya Kamsky    schedule 09.10.2012
comment
Спасибо, но я читал, что агрегация ограничена 20 тысячами элементов... И я хочу сопоставить только несколько имен объектов, у меня их много... более 20 тысяч. Итак, я сделал это с помощью MapReduce. Спасибо за вашу помощь! - person B0ltz; 15.10.2012
comment
Я не уверен, к чему относится ограничение - возвращаемый результат ограничен 16 МБ (максимальный размер документа) - поэтому, если ваш возвращаемый результат будет намного больше, вы определенно не сможете использовать структуру агрегации. Map/reduce не имеет такого же ограничения, но может быть более сложным в написании/сопровождении... И определенно намного медленнее. - person Asya Kamsky; 16.10.2012