Заявката не е толкова сложна, колкото може да изглежда на пръв поглед - заявката за намиране на всички документи, които се "припокриват" с дадения ви диапазон, е:
db.test.find( { "startTime" : { "$lt" : new_end_time },
"endTime" : { "$gt": new_start_time }
}
)
Това ще съпостави всеки документ с начална дата, по-ранна от нашата крайна дата и крайна дата, по-голяма от началния ни час. Ако визуализирате диапазоните като точки на линия:
<преди>-----|*********|----------|****|-----------|*** ***||********|--- s1 e1 s2 e2 s3 e3s4 e4двойките sX-eX представляват съществуващи диапазони. Ако вземете нов s5-e5, можете да видите, че ако елиминираме двойки, които започват след нашата крайна дата (те не могат да ни припокриват) и след това елиминираме всички двойки, които завършват преди началната ни дата, ако не ни е останало нищо, тогава е добре да вмъкнем.
Това условие ще бъде обединяване на всички документи с крайна дата $lte
нашето начало и тези с начална дата $gte
нашите включват всички документи, които вече са в колекцията. Нашата заявка преобръща това, за да се увери, че нито един документ не отговаря на обратното на това условие.
Що се отнася до производителността, жалко е, че съхранявате датите си само като низове. Ако сте ги съхранили като времеви отпечатъци (или произволно число, наистина), можете да накарате тази заявка да използва по-добре индексите. Както е, за ефективност бихте искали да имате индекс на { "startTime":1, "endTime":1 }
.
Лесно е да разберете дали диапазонът, който искате да вмъкнете, припокрива съществуващи диапазони, но на втория ви въпрос:
Няма начин да го направите с вмъквания, тъй като те не приемат заявка (т.е. не са условни).
Можете обаче да използвате актуализации с upsert условие. Може да вмъкне, ако условието не съвпада с нищо, но ако съвпада, ще се опита да актуализира съответстващия документ!
Така че трикът, който бихте използвали, е да направите актуализацията noop и да зададете полетата, от които се нуждаете, само на upsert. От 2.4 има $setOnInsert
оператор за актуализиране. Цялото нещо би изглеждало така:
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 })
Току-що направих една и съща „актуализация“ два пъти – първият път нямаше документ(и) за припокриване, така че актуализацията извърши „upsert“, което можете да видите в WriteResult
върна се.
Когато го пуснах втори път, той щеше да се припокрие (разбира се), така че се опита да актуализира съответстващия документ, но забеляза, че няма работа за вършене. Можете да видите, че върнатото nMatched е 1, но нищо не е вмъкнато или променено.