แบบสอบถามการนับขั้นสูงของ 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, baz)

แต่ตอนนี้ฉันต้องการนับ foo และ bar เฉพาะในกรณีที่ bar เก่า มากกว่า foo (โดยใช้เขตข้อมูลเวลา)...
< strong>จำนวน
ของคอนเทนเนอร์ที่มีวัตถุ 1 (foo),
จำนวน ของคอนเทนเนอร์ที่มีวัตถุ 1 และ 2 (foo และ bar) และ foo.time ‹ bar.time
count ของคอนเทนเนอร์ที่มีอ็อบเจ็กต์ 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 ในเชลล์ (จาวาสคริปต์)

โปรดทราบว่าฉันได้แยกสิ่งนี้ออกเป็นหลายบรรทัดเพื่อให้อ่านง่าย ข้อความค้นหาจริงคือบรรทัดสุดท้าย ฉันเคยใช้ 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,000 องค์ประกอบ... และฉันต้องการจับคู่ชื่อวัตถุเพียงไม่กี่ชื่อ ฉันมีพวกมันเยอะมาก... มากกว่า 20,000 รายการ ดังนั้นฉันจึงทำสิ่งนั้นด้วย MapReduce ในตอนนี้ ขอบคุณสำหรับความช่วยเหลือของคุณ! - person B0ltz; 15.10.2012
comment
ฉันไม่แน่ใจว่าขีดจำกัดนี้หมายถึงอะไร - ผลลัพธ์ที่ส่งคืนถูกจำกัดไว้ที่ 16MB (ขนาดเอกสารสูงสุด) - ดังนั้นหากผลลัพธ์ที่คุณส่งคืนจะใหญ่กว่ามาก คุณจะไม่สามารถใช้กรอบงานการรวมได้อย่างแน่นอน Map/reduce ไม่มีข้อจำกัดเหมือนกัน แต่การเขียน/บำรุงรักษาอาจซับซ้อนกว่า... และจะช้ากว่ามากอย่างแน่นอน - person Asya Kamsky; 16.10.2012