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.