简体   繁体   English

Mongodb/mongoose 查询完全重叠的日期(可以跨越多个文档)

[英]Mongodb/mongoose query for completely overlapping dates (that could span multiple documents)

I'm having some issues designing a query that deals with overlapping dates.我在设计处理重叠日期的查询时遇到了一些问题。

So here's the scenario, I can't reveal too much about the actual project but here is a similar example.所以这是场景,我不能透露太多关于实际项目的信息,但这里有一个类似的例子。 Lets say I have a FleaMarket .假设我有一个FleaMarket It has a bunch of data about itself such as name , location , etc.它有一堆关于它自己的数据,比如namelocation等。

So a FleaMarket would have many Stalls , that are available to be booked for a portion of the year (as short as 2 days, as long as all year sort of thing).因此,一个FleaMarket将有许多Stalls ,可用来预订全年的一部分(如短至2天,只要全年的那种东西)。 So the FleaMarket needs to specify when in a year it will be open.因此, FleaMarket需要指定一年内的开放时间。 Most scenarios would either be open all year, or all summer/fall, but it could possible be broken down further (because seasons determine pricing).大多数场景要么全年开放,要么整个夏季/秋季开放,但可能会进一步细分(因为季节决定定价)。 Each FleaMarket would define their Seasons which would include a startDate and endDate (including year).每个FleaMarket将定义自己的Seasons ,其中将包括一个startDateendDate (含一年)。

Here's an ERD to model this example:这是一个用于建模此示例的 ERD:

在此处输入图片说明

When a user attempts to book a Stall , they have already selected a FleaMarket (although ideally it would be nice to search based on availability in the future).当用户尝试预订Stall ,他们已经选择了FleaMarket (尽管理想情况下,根据未来的可用性进行搜索会很好)。 It's really easy to tell if a Stall is already booked for the requested dates:很容易判断是否已在要求的日期预订了Stall

bookings = await Booking.find({
  startDate: { $lt: <requested end date> },
  endDate: { $gt: <requested start date> },
  fleaMarketId: <flea market id>,
}).select('stallId');
bookedIds = bookings.map(b => b.stallId);

stalls = await Stall.find({
  fleaMarketId: <flea marked id>,
  _id: { $nin: bookedIds }
});

The issue I'm having is determining if a Stall is available for the specified Season .我遇到的问题是确定是否有Stall可用于指定的Season The problem comes that 2 seasons could be sequential, so you could make a booking that spans 2 seasons.问题是 2 个季节可能是连续的,因此您可以进行跨 2 个季节的预订。

I originally tried a query like so:我最初尝试过这样的查询:

seasons = await Season.find({
  fleaMarketId: <flea market id>,
  startDate: { $lt: <requested end date> },
  endDate: {$gt: <requested start date> }
});

And then programatically checked if any returned seasons were sequential, and plucked the available stalls from that that existed in all seasons.然后以编程方式检查任何返回的季节是否是连续的,并从所有季节都存在的摊位中挑选可用的摊位。 But unfortunately I just realized this won't work if the requested date only partially overlaps with a season (ex: requested Jan 1 2020 - Jan 10 2020 , but the season is defined as Jan 2 2020 - May 1 2020 )但不幸的是,我刚刚意识到如果请求的日期仅与一个季节部分重叠,这将不起作用(例如:请求Jan 1 2020 - Jan 10 2020 ,但该季节定义为Jan 2 2020 - May 1 2020

Is there a way I can handle checking for completely overlapping dates that could possible overlap with multiple documents?有没有办法检查可能与多个文档重叠的完全重叠的日期? I was thinking about calculating and storing the current and future available season dates (stored as total ranges) denormalized on the Stall .我正在考虑计算和存储当前和未来可用的季节日期(存储为总范围)在Stall上非规范化。

At this point I'm almost thinking I need to restructure the schema quite a bit.在这一点上,我几乎在想我需要对架构进行相当多的重构。 Any recommendations?有什么建议吗? I know this seems very relational, but pretty much everywhere else in the application doesn't really do much with the relationships.我知道这看起来非常相关,但应用程序中的其他几乎所有地方都没有真正处理这些关系。 It's just this search that is quite problematic.正是这种搜索是相当有问题的。

Update :更新

I just had the thought of maybe creating some sort of Calendar Document that can store a centralized list of availability for a FleaMarket , that would do a rolling update to only store future and present data, and slowly wiping away historical data, or maybe archiving it in a different format.我只是想到可能会创建某种Calendar文档,可以存储FleaMarket的集中可用性列表,这将进行滚动更新以仅存储未来和当前数据,并慢慢擦除历史数据,或者可能将其存档以不同的格式。 Perhaps this will solve my issue, I will be discussing it with my team soon.也许这会解决我的问题,我将很快与我的团队讨论。

So as I said in an update in my post, I came up with the idea to create a rolling calendar.因此,正如我在帖子的更新中所说,我想出了创建滚动日历的想法。

For anyone who is interested, here's what I got:对于任何有兴趣的人,这是我得到的:

I created an Availability collection, that contains documents like the following:我创建了一个Availability集合,其中包含如下文档:

{
  marketId: ObjectId('5dd705c0eeeaf900450e7009'),
  stallId: ObjectId('5dde9fc3bf30e500280f80ce'),
  availableDates: [
    {
      date: '2020-01-01T00:00:00.000Z',
      price: 30.0,
      seasonId: '5dd708e7534f3700a9cad0e7',
    },
    {
      date: '2020-01-02T00:00:00.000Z',
      price: 30.0,
      seasonId: '5dd708e7534f3700a9cad0e7',
    },
    {
      date: '2020-01-03T00:00:00.000Z',
      price: 35.0,
      seasonId: '5dd708e7534f3700a9cad0e8',
    }
  ],
  bookedDuring: [
    '2020-01-01T00:00:00.000Z'
    '2020-01-02T00:00:00.000Z'
  ]
}

Then handling updates to this collection:然后处理此集合的更新:

Seasons四季

  • when creating, $push new dates onto each stall (and delete dates from the past)创建时,将新日期推到每个摊位上(并删除过去的日期)
  • When updating, remove the old dates, and add on the new ones (or calculate difference, either works depending on the integrity of this data)更新时,删除旧日期并添加新日期(或计算差异,取决于此数据的完整性)
  • When deleting, remove dates删除时,删除日期

Stalls摊位

  • When creating, insert records for associated seasons创建时,插入关联季节的记录
  • When deleting, delete records from availability collection删除时,从可用性集合中删除记录

Bookings预订

  • When creating, add dates to bookedDuring创建时,将日期添加到bookedDuring
  • When updating, add or remove dates from bookedDuring更新时,从bookedDuring添加或删除日期

Then to find available stalls for a market, you can query where { marketId: /* market's ID */, availableDates.date: { $all: [/* each desired day */], bookedDuring: { $nin: [/* same dates */ ] } }} and then pluck out the stallId然后要查找市场的可用摊位,您可以查询 where { marketId: /* market's ID */, availableDates.date: { $all: [/* each desired day */], bookedDuring: { $nin: [/* same dates */ ] } }}然后取出stallId

And to find markets that have available, do { availableDates.dates: { $all: [/* each desired day */], bookedDuring: { $nin: [/* same dates */ ] } }} select distinct marketIds要查找可用的市场,请执行{ availableDates.dates: { $all: [/* each desired day */], bookedDuring: { $nin: [/* same dates */ ] } }}选择不同的marketIds

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM