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

Dotaz a vložení pomocí jediného příkazu

Dotaz není tak složitý, jak se na první pohled může zdát – dotaz na nalezení všech dokumentů, které se „překrývají“ zadaný rozsah, je:

db.test.find( { "startTime" : { "$lt" : new_end_time }, 
                "endTime"   : { "$gt": new_start_time } 
            } 
)

To bude odpovídat všem dokumentům s počátečním datem dřívějším než naše koncové datum a koncovým datem vyšším než je náš čas zahájení. Pokud si rozsahy představíte jako body na přímce:

-----|*********|----------|****|-----------|******||********|---
    s1         e1         s2   e2         s3     e3s4       e4

páry sX-eX představují existující rozsahy. Pokud si vezmete nový s5-e5, uvidíte, že pokud odstraníme páry, které začínají po naše koncové datum (nemohou nás překrývat) a pak vyřadíme všechny páry, které končí před naším počátečním datem, pokud nám nic nezbyde, tak je dobré vložit.

Touto podmínkou by bylo spojení všech dokumentů s koncovým datem $lte náš začátek a ty s datem zahájení $gte naše zahrnují všechny dokumenty, které jsou již ve sbírce. Náš dotaz to obrací, abychom se ujistili, že žádné dokumenty nesplňují opak této podmínky.

Pokud jde o výkon, je nešťastné, že data ukládáte pouze jako řetězce. Pokud jste je uložili jako časová razítka (nebo jakékoli číslo, opravdu), mohli byste tento dotaz lépe využít k indexům. Jak to je, pro výkon byste chtěli mít index na { "startTime":1, "endTime":1 } .

Je snadné zjistit, zda se rozsah, který chcete vložit, překrývá s existujícími rozsahy, ale k vaší druhé otázce:

Neexistuje žádný správný způsob, jak to udělat s vložkami, protože neberou dotaz (tj. nejsou podmíněné).

Můžete však použít aktualizace s podmínkou upsert. Může vložit, pokud podmínka neodpovídá ničemu, ale pokud se shoduje, pokusí se aktualizovat odpovídající dokument!

Takže trik, který byste použili, je udělat aktualizaci jako smyčku a nastavit pole, která potřebujete, pouze na upsert. Od verze 2.4 existuje $setOnInsert operátor aktualizovat. Celá věc by vypadala asi takto:

db.test.update( 
   { startTime: { "$lt" : new_end_time }, "endTime" : { "$gt": new_start_time } }, 
   { $setOnInsert:{ startTime:new_start_time, endTime: new_end_time}},
   {upsert:1}
)
WriteResult({
"nMatched" : 0,
"nUpserted" : 1,
"nModified" : 0,
"_id" : ObjectId("538e0f6e7110dddea4383938")
})
db.test.update(
   { startTime:{ "$lt" : new_end_time }, "endTime" : { "$gt": new_start_time } },
   { $setOnInsert:{ startTime:new_start_time, endTime: new_end_time}},
   {upsert:1}
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })

Právě jsem dvakrát provedl stejnou "aktualizaci" - poprvé se nevyskytl žádný překrývající se dokument(y), takže aktualizace provedla "upsert", který můžete vidět v WriteResult vrátilo se to.

Když jsem to spustil podruhé, překrýval se (samozřejmě sám), takže se pokusil aktualizovat odpovídající dokument, ale všiml si, že není co dělat. Můžete vidět, že vrácená hodnota nMatched je 1, ale nic nebylo vloženo ani změněno.



  1. Jak získat délku kurzoru z mongodb pomocí pythonu?

  2. Zamyká MongoDB MapReduce databázi

  3. Jak porovnat MongoDB s YCSB?

  4. MongoDB ORM pro Python?