MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

ограничаване и сортиране на всяка група по в mongoDB с помощта на агрегиране

Най-добрият ви вариант тук е да стартирате отделни заявки за всяка „Държава“ (в идеалния случай паралелно) и да върнете комбинираните резултати. Заявките са доста прости и просто връщат първите 2 стойности след прилагане на сортиране върху стойността на рейтинга и ще се изпълнят доста бързо, дори ако трябва да извършите множество заявки, за да получите пълния резултат.

Рамката за агрегиране не е подходяща за това сега и дори в близко бъдеще. Проблемът е, че няма такъв оператор, който да "ограничава" резултата от всяко групиране по някакъв начин. Така че, за да направите това, вие основно трябва да $push цялото съдържание в масив и извлечете "топ n" стойностите от него.

Настоящите операции, необходими за извършване на това, са доста ужасни и основният проблем е, че резултатите вероятно ще надхвърлят ограничението на BSON от 16 MB на документ в повечето реални източници на данни.

Също така има n сложността на това поради начина, по който трябва да го направите точно сега. Но само за демонстрация с 2 елемента:

db.collection.aggregate([
    // Sort content by country and rating
    { "$sort": { "Country": 1, "rating": -1 } },

    // Group by country and push all items, keeping first result
    { "$group": {
        "_id": "$Country",
        "results": {
            "$push": {
                "name": "$name", 
                "rating": "$rating",
                "id": "$id"
            }
        },
        "first": { 
            "$first": {
                "name": "$name", 
                "rating": "$rating",
                "id": "$id"
            }
        }
    }},

    // Unwind the array
    { "$unwind": "results" },

    // Remove the seen result from the array
    { "$redact": {
        "$cond": {
            "if": { "$eq": [ "$results.id", "$first.id" ] },
            "then": "$$PRUNE",
            "else": "$$KEEP"
        }
    }},

    // Group to return the second result which is now first on stack
    { "$group": {
        "_id": "$_id",
        "first": { "$first": "$first" },
        "second": { 
            "$first": {
                "name": "$results.name", 
                "rating": "$results.rating",
                "id": "$results.id"
            }
        }
    }},

    // Optionally put these in an array format
    { "$project": {
        "results": { 
            "$map": {
                "input": ["A","B"],
                "as": "el",
                "in": {
                    "$cond": {
                        "if": { "$eq": [ "$$el", "A" ] },
                        "then": "$first",
                        "else": "$second"
                    }
                }
            }
        }
    }}
])

Това дава резултата, но не е страхотен подход и става много по-сложен с итерации за по-високи граници или дори когато групировките вероятно имат по-малко от n резултати, които да се върнат в някои случаи.

Текущата поредица за разработка ( 3.1.x ) към момента на писане има $slice оператор, който прави това малко по-просто, но все още има същия "размер" капан:

db.collection.aggregate([
    // Sort content by country and rating
    { "$sort": { "Country": 1, "rating": -1 } },

    // Group by country and push all items, keeping first result
    { "$group": {
        "_id": "$Country",
        "results": {
            "$push": {
                "name": "$name", 
                "rating": "$rating",
                "id": "$id"
            }
        }
    }},
    { "$project": {
        "results": { "$slice": [ "$results", 2 ] }
    }}
])

Но основно докато рамката за агрегиране има някакъв начин да "ограничи" броя на елементите, произведени от $push или подобен оператор за "лимит" на групиране, тогава рамката за агрегиране всъщност не е оптималното решение за този тип проблем.

Прости заявки като тази:

db.collection.find({ "Country": "USA" }).sort({ "rating": -1 }).limit(1)

Изпълнение за всяка отделна държава и в идеалния случай при паралелна обработка чрез цикъл на събитие от нишка с комбиниран резултат създава най-оптималния подход в момента. Те извличат само това, което е необходимо, което е големият проблем, с който рамката за агрегиране все още не може да се справи в такова групиране.

Така че вместо това потърсете поддръжка, за да направите тези „комбинирани резултати от заявка“ по най-оптималния начин за избрания от вас език, тъй като ще бъде много по-малко сложно и много по-производително, отколкото да хвърлите това в рамката за агрегиране.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Актуализирайте подмножество от полета с Mongoose

  2. c# mongodb търсене, чувствително към главни и малки букви

  3. Как да обработваме правилно заявките за страниране с mongodb и php?

  4. TypeError:db.collection не е функция

  5. Как мога да използвам partialFilterExpression върху модел mongoose