【问题标题】:Check if date range conflicts with current documents MongoDB检查日期范围是否与当前文档 MongoDB 冲突
【发布时间】:2020-01-08 19:34:13
【问题描述】:

这个问题有一层复杂性,我不确定可以解决的最佳做法。

尝试创建一个预订日历,为其所选范围提供下一个可用日期。我们已经取消了一些空白。

当前功能只取最远的结束日期并在第二天提供服务,这变得非常不准确,并且由于取消而留下了空白。

例如。用户希望在最近的可用日期预订 10 天。在数据库中,适合该用户的 2 个文档之间存在差距,我如何查询以验证此可用性?

数据库文档示例

{
    "start_date" : "2020-02-06T19:58:25.430Z",
    "end_date" : "2020-02-16T19:58:25.430Z"
},
{
    "start_date" : "2020-02-17T19:58:25.430Z",
    "end_date" : "2020-02-27T19:58:25.430Z"
},
{
    "start_date" : "2020-03-21T19:58:25.430Z",
    "end_date" : "2020-03-31T19:58:25.430Z"
},

在第二份和第三份文件之间,用户可以申请 2 周的时间。目前,此用户将收到 2020-04-01 作为下一个可用性。我想让他们选择通过发送 2020-02-28 作为下一个可用性来要求取消日期。

在默认为最远的 end_date 之前,如何查询 mongodb 以查看文档范围之间是否有 x 天的可用量?

【问题讨论】:

    标签: node.js mongodb mongodb-query


    【解决方案1】:

    一个想法:创建一个单独的cancelled 集合,并将所有已取消的约会移动到此集合中。

    如果要进行新的预约,请先搜索此cancelled 集合,以查找因取消而导致的任何空缺。如果没有找到合适的,则按照您当前的方法继续到最远的结束日期。

    插图:

    > db.appointments.find()
    { "_id" : 0, "start" : 1, "end" : 2, "duration" : 1, "name": "John" }
    { "_id" : 1, "start" : 2, "end" : 4, "duration" : 2, "name": "Jane" }
    { "_id" : 2, "start" : 4, "end" : 5, "duration" : 1, "name": "Jack" }
    
    // Jane cancelled the appt with _id 1
    > c = db.appointments.findOne({_id: 1})
    > db.cancelled.insert(c)
    > db.appointments.deleteOne({_id: 1})
    
    // current state of appointments
    > db.appointments.find()
    { "_id" : 0, "start" : 1, "end" : 2, "duration" : 1, "name": "John" }
    { "_id" : 2, "start" : 4, "end" : 5, "duration" : 1, "name": "Jack" }
    
    // Bob wanted to make an appointment spanning two "time units". Is it available?
    > db.cancelled.findOne({duration: 2})
    { "_id" : 1, "start" : 2, "end" : 4, "duration" : 2, "name" : "Jane" }
    
    // If Bob agreed to take over Jane's time slot
    // reinsert the document from "cancelled" to "appointments", changing the name
    > a = db.cancelled.findOne({duration: 2})
    > a.name = "Bob"
    > db.appointments.insert(a)
    > db.cancelled.deleteOne({_id:1})
    
    // end state of appointments
    > db.appointments.find().sort({start: 1})
    { "_id" : 0, "start" : 1, "end" : 2, "duration" : 1, "name": "John" }
    { "_id" : 1, "start" : 2, "end" : 4, "duration" : 2, "name": "Bob" }
    { "_id" : 2, "start" : 4, "end" : 5, "duration" : 1, "name": "Jack" }
    

    请注意,在此插图中,我还记录了每个约会的持续时间,以便可以有效地搜索它们。最终状态是来自 Jane 的 _id: 1 被 Bob 替换,cancelled 集合中没有任何内容。

    为确保appointmentscancelled 集合都正确更新,您可能需要使用自MongoDB 4.0 起提供的Transactions

    【讨论】:

    • 嗯.. 我也许可以稍微简化一下这一步。有一个标志可以将它们设置为取消与否,我没有将完整的数据结构发布为大数据,并且有很多与我要完成的工作无关的数据。我不一定需要另一个集合,只需拉回已标记为已取消的数据。 Kinda 也有其自身的复杂性,用户必须预订确切的日期,否则可能存在重叠,或者在双人收藏的情况下,如果用户没有整整 10 天,只有 5 天,我仍然有可以预订的空档。
    • 当然我发布的只是一个插图,而不是一个完整的解决方案。我想实际的实施会比这更复杂,包括将取消的约会分成多个时段的步骤。
    • 是的,谢谢你的想法。我一直在这个问题上陷入困境,所以我开始思考一些我没有考虑过的替代解决方案。
    【解决方案2】:

    让它在我的大脑中发酵一周后,我想出了一个解决方案。我无法从查询 mongodb 中得到想要的结果。我不得不使用 javascript 来比较一些文档。不确定运行时间将如何保持,对我来说这是另一天的问题。

    上周我在谷歌搜索中遇到了我自己的问题,我想我会添加我的解决方案。

    //Find all the documents that have an end date greater than today, sort them based // on the start date to order documents
    let sort = await db.collection(COLLECTION)
            .find({end_date : { $gte:new Date() }
          })
            .sort({start_date: 1 })
            .toArray();
    
    //Set the nextDate variable
          let nextDate;
          if(sort.length >= 2){
    
    //Javascript iteration if there are more than 2 documents returned from sorting
    
            for (let i = 0; i < sort.length; i++) {
    
              var startDate = Date.parse(sort[i].end_date);
    
    //endDate is ternary incase the amount of documents is odd number
    
              var endDate = sort[i + 1] ? Date.parse(sort[i + 1].start_date) : new Date()
              var timeDiff = endDate - startDate;
              var daysDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24))
    
    
    //Get the day difference between the date if the difference is greater than the //days alloted by user return the end date
    
              if(daysDiff > days) {
                return nextDate = sort[i].end_date
              } 
    
            }
    //If no days have room for the decided days, return the last document in array
    
              return nextDate = sort[sort.length - 1].end_date
    
    //If only one document, return end date
    
          } else if (sort.length === 1) {
            nextDate = sort[0].endDate
    
    //No documents found, return todays date as it is available.
          } else {
            nextDate = new Date()
          }
    

    这实际上非常适合我需要它做的事情。希望能得到很好的重构并且可以简化。

    【讨论】:

      猜你喜欢
      • 2012-08-25
      • 1970-01-01
      • 1970-01-01
      • 2015-02-13
      • 2016-01-25
      • 2020-03-21
      • 2018-07-01
      • 1970-01-01
      • 2016-02-15
      相关资源
      最近更新 更多