sql >> Databáze >  >> NoSQL >> MongoDB

seřadit podle hodnoty vloženého objektu v Mongodb

Pokud potřebujete něco takového vypočítat za běhu s „filtrovaným“ obsahem z pole určujícím pořadí řazení, pak nejlépe uděláte něco s .aggregate() změnit tvar a určit hodnotu řazení takto:

db.collection.aggregate([
    // Pre-filter the array elements
    { "$project": {
        "tags": 1,
        "score": {
            "$setDifference": [
                { "$map": {
                    "input": "$tags",
                    "as": "tag",
                    "in": {
                        "$cond": [
                            { "$eq": [ "$$el.id", "t1" ] },
                            "$$el.score",
                            false
                        ]
                    }
                }},
                [false]
            ]
        }
    }},
    // Unwind to denormalize
    { "$unwind": "$score" },
    // Group back the "max" score
    { "$group": {
        "_id": "$_id",
        "tags": { "$first": "$tags" },
        "score": { "$max": "$score" }
    }},
    // Sort descending by score
    { "$sort": { "score": -1 } }
])

Kde se první část kanálu používá k "předfiltrování" obsahu pole (stejně jako k zachování původního pole) pouze na ty hodnoty "skóre", kde se id rovná "t1". To se provádí zpracováním $map který aplikuje podmínku na každý prvek prostřednictvím $cond určit, zda vrátit "skóre" pro daný prvek nebo false .

$setDifference operace provede porovnání s polem jednoho prvku [false] který účinně odstraní všechny false hodnoty vrácené z $map . Jako "set" to také odstraní duplicitní položky, ale pro účely třídění je to dobrá věc.

S polem redukovaným a přeformátovaným na hodnoty zpracujete $unwind připraven na další fázi, kdy se bude zabývat hodnotami jako jednotlivými prvky. $group fáze v podstatě platí $max na "skóre", aby se vrátila nejvyšší hodnota obsažená ve filtrovaných výsledcích.

Pak už jen stačí použít $sort na stanovenou hodnotu objednat doklady. Přirozeně, pokud to chcete naopak, použijte $min a místo toho seřadit ve vzestupném pořadí.

Samozřejmě přidejte $match fázi na začátek, pokud vše, co opravdu chcete, jsou dokumenty, které ve skutečnosti obsahují hodnoty "t1" pro id v rámci značek. Ale tato část je nejméně relevantní pro třídění podle filtrovaných výsledků, kterých chcete dosáhnout.

Alternativou k počítání je dělat to všechno, když zapisujete položky do pole v dokumentech. Trochu chaotický, ale vypadá to nějak takto:

db.collection.update(
    { "_id": docId },
    {
        "$push": { "tags": { "id": "t1", "score": 60 } },
        "$max": { "maxt1score": 60 },
        "$min": { "mint1score": 60 }
    }
)

Zde je $max Operátor aktualizace nastaví hodnotu pro zadané pole pouze v případě, že je nová hodnota větší než stávající hodnota nebo jinak ještě neexistuje žádná vlastnost. Opačný případ platí pro $min , kde pouze v případě, že bude menší než to, bude nahrazeno novou hodnotou.

To by samozřejmě mělo za následek přidání různých dalších vlastností do dokumentů, ale konečným výsledkem je řazení je značně zjednodušené:

db.collection.find().sort({ "maxt1score": -1 })

A poběží to mnohem rychleji než výpočty pomocí agregačního kanálu.

Zvažte tedy zásady návrhu. Strukturovaná data v polích, kde chcete filtrované a spárované výsledky pro třídění, znamenají výpočet za běhu, abyste určili, podle které hodnoty se mají třídit. Přidání dalších vlastností do dokumentu na .update() znamená, že můžete jednoduše odkazovat na tyto vlastnosti a přímo třídit výsledky.



  1. Nativní maskování MongoDB (3. metoda)

  2. CHYBA:Nelze zapsat soubor pid do /var/run/mongodb/mongod.pid:Žádný takový soubor nebo adresář inf fedora 20

  3. Jak modelovat systém hlasování Líbí se pomocí MongoDB

  4. ServerSelectionTimeoutError errno 11001 getaddrinfo se nezdařilo python