Kueri penghitungan lanjutan MongoDB, bergantung pada konten dokumen

Saya punya masalah dengan kueri penghitungan lanjutan dengan MongoDB.

Saya mencoba menghitung objek di dalam bidang dokumen, tetapi hanya jika elemen sebelumnya yang cocok dengan kueri ada dan lebih tua< /strong> dalam larik.

Biar saya jelaskan....

Saya mempunyai dokumen penampung, yang terlihat seperti:

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

Di dalam bidang objek:
Saya memiliki dokumen objek yang terlihat seperti:

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

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

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

Untuk saat ini saya menghitung berapa banyak dokumen penampung yang berisi:
jumlah penampung dengan objek 1 (foo),
jumlah kontainer dengan objek 1 dan 2 (foo dan bar),
jumlah kontainer dengan objek 1, 2 dan 3 (foo, bar, baz)

Namun sekarang saya ingin menghitung foo dan bar hanya jika bar lebih tua dari foo (menggunakan kolom waktu)...
< strong>count
container dengan objek 1 (foo),
count container dengan objek 1 dan 2 (foo dan bar), AND foo.time ‹ bar.time
jumlah kontainer dengan objek 1, 2 dan 3 (foo, bar , baz) DAN foo.time ‹ bar.time ‹ baz.time

Masalahnya adalah bidang waktu perlu diubah untuk setiap kontainer. Dengan kata lain: Bagaimana saya bisa menggunakan kueri dinamis per dokumen

berikut contoh kodenya:

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);
}

Saya baru di MongoDB, dan saya benar-benar tidak tahu praktik terbaik apa yang bisa dilakukan untuk melakukannya secara efisien!

Salam!


person B0ltz    schedule 05.10.2012    source sumber
comment
apakah kamu menggunakan 2.2? dan apakah jumlah kondisi ini cukup kecil? apakah foo ‹ bar dan foo‹bar‹baz mewakili kueri aktual yang harus Anda buat atau adakah ketentuan lainnya?   -  person Asya Kamsky    schedule 08.10.2012
comment
Hai, ya, saya menggunakan 2.2.0, saya harus mencocokkan sekitar 5 atau lebih objek yang ada seperti foo dan bar.   -  person B0ltz    schedule 08.10.2012


Jawaban (1)


Inilah cara Anda melakukan ini dengan Aggregation Framework di shell (javascript).

Perhatikan bahwa saya telah membaginya menjadi beberapa baris agar mudah dibaca, kueri sebenarnya adalah baris terakhir. Saya pernah menggunakan foo bar dan baz tapi tentu saja Anda ingin menyesuaikan dengan yang lebih sesuai.

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
Terima kasih, tetapi saya telah membaca bahwa agregasi dibatasi hingga 20 ribu elemen... Dan saya hanya ingin mencocokkan beberapa nama objek, saya punya banyak... lebih dari 20 ribu. Jadi saya sudah melakukannya dengan MapReduce untuk saat ini. terima kasih atas bantuan Anda! - person B0ltz; 15.10.2012
comment
Saya tidak yakin apa yang dimaksud dengan batasan tersebut - hasil yang dikembalikan dibatasi hingga 16MB (ukuran dokumen maksimal) - jadi jika hasil yang Anda kembalikan akan jauh lebih besar maka Anda pasti tidak dapat menggunakan kerangka agregasi. Map/reduce tidak memiliki batasan yang sama tetapi bisa lebih rumit untuk ditulis/dipelihara... Dan pastinya jauh lebih lambat. - person Asya Kamsky; 16.10.2012