【问题标题】:Querying array of events to find if the event I'm adding is overlapping (Express/Mongoose)查询事件数组以查找我添加的事件是否重叠(Express/Mongoose)
【发布时间】:2018-08-04 04:54:50
【问题描述】:

我有一个带有文档集合的 mongo db,其中每个元素都有一个繁忙的数组来收集事件。猫鼬模型如下:

busy: [{
      _id : Schema.Types.ObjectId,
      isBusy : Boolean,
      eventType : String,
      title : String,
      startDate : Date,
      endDate : Date,
      event: {type: Schema.Types.ObjectId, ref: 'Event', index: true },
    }],

当它被填充时,我想查询数组中没有在我尝试添加的事件同时发生的事件的所有文档,所以我只能选择不忙的文档那一刻。

我使用的查询是

{
  "user.busy": {
    $not: {
      $elemMatch: {
        'startDate': {
          $gte: startDate,
          $lt: endDate
        },
        'endDate': {
          $gte: startDate,
          $lt: endDate
        },
        isBusy: true
      }
    }
  }
}

而且它不起作用。 关于我应该如何继续执行此操作的任何提示?

--- 样本数据

这是一个来自我的数据库的繁忙数组示例

"busy" : [ 
            {
                "isBusy" : true,
                "eventType" : "Shooting",
                "title" : "Shooting",
                "startDate" : ISODate("2018-08-23T00:00:28.000Z"),
                "endDate" : ISODate("2018-08-23T03:00:28.000Z"),
                "event" : ObjectId("5b5573fcba399fababcb200d")
            }, 
            {
                "isBusy" : true,
                "eventType" : "Shooting",
                "title" : "Shooting",
                "startDate" : ISODate("2018-08-23T06:30:28.000Z"),
                "endDate" : ISODate("2018-08-23T09:30:28.000Z"),
                "event" : ObjectId("5b557410ba399fababcb2013")
            }, 
            {
                "isBusy" : true,
                "eventType" : "Shooting",
                "title" : "Shooting",
                "startDate" : ISODate("2018-08-23T10:11:06.000Z"),
                "endDate" : ISODate("2018-08-23T13:11:06.000Z"),
                "event" : ObjectId("5b5580216a5615aca0d089e0")
            }, 
            ],

-- 编辑 1

由于查询在数据库上进行原始操作时有效,因此可能是我的 Mongoose 实现中的某些内容,按如下方式完成

Element.find({ 
 "user.busy" : 
   { $not : 
     { $elemMatch : 
       {
         'startDate' : { $gte: startDate, $lt: endDate }, 
         'endDate' : { $gte: startDate, $lt: endDate }, 
         isBusy : true 
       } 
     } 
   } 
 })
.exec()
.then(...)

【问题讨论】:

  • 请发布您的示例文档和输出
  • 你能解释一下什么场景不工作吗?为什么查询中有 isBusy 标志?
  • isBusy 标志是因为用户可以使用相同的字段在日历中创建其他类型的事件,这些事件不会使它们对系统来说是忙碌的
  • 我试图删除 isBusy: true 但没有任何变化。唯一可行的情况是当我尝试创建一个重复的事件(相同的开始日期/结束日期)时。还有一点需要注意的是日期包括时间
  • 为什么是user.busy?尝试直接访问数组,即busy

标签: node.js mongodb express mongoose


【解决方案1】:

输入:

{
    "_id" : ObjectId("5b6495b4611de4551f5eb8d4"),
    "user" : {
        "busy" : [ 
            {
                "_id" : ObjectId("5b6493b5611de4551f5eb878"),
                "isBusy" : true,
                "eventType" : "Shooting",
                "title" : "Shooting",
                "startDate" : ISODate("2018-01-23T00:00:28.000Z"),
                "endDate" : ISODate("2018-08-23T03:00:28.000Z"),
                "event" : ObjectId("5b5573fcba399fababcb200d")
            }, 
            {
                "_id" : ObjectId("5b649486611de4551f5eb89f"),
                "isBusy" : true,
                "eventType" : "Shooting",
                "title" : "Shooting",
                "startDate" : ISODate("2018-08-23T10:11:06.000Z"),
                "endDate" : ISODate("2018-10-23T13:11:06.000Z"),
                "event" : ObjectId("5b5580216a5615aca0d089e0")
            }
        ]
    }
}    
{
    "_id" : ObjectId("5b6495e5611de4551f5eb8df"),
    "user" : {
        "busy" : [ 
            {
                "_id" : ObjectId("5b6493b5611de4551f5eb878"),
                "isBusy" : true,
                "eventType" : "Playing Games",
                "title" : "MORTAL KOMBAT",
                "startDate" : ISODate("2017-04-23T00:00:28.000Z"),
                "endDate" : ISODate("2017-06-23T03:00:28.000Z"),
                "event" : ObjectId("5b5573fcba399fababcb200d")
            }, 
            {
                "_id" : ObjectId("5b6493bf611de4551f5eb87a"),
                "isBusy" : true,
                "eventType" : "Coding",
                "title" : "JavaScript",
                "startDate" : ISODate("2017-07-23T06:30:28.000Z"),
                "endDate" : ISODate("2017-08-23T09:30:28.000Z"),
                "event" : ObjectId("5b557410ba399fababcb2013")
            }
        ]
    }
}

$not 的一般经验法则是创建一个您知道它有效的查询并使用 $not 否定它。 所以你有find me x, and then everything not equal (and not existing as well) to x。所以让我们创建find me x:

var startDate = ISODate("2017-11-23T00:00:28.000Z"),
    endDate = ISODate("2018-09-23T03:00:28.000Z")

db.getCollection('busy').find({
  "user.busy": {
      $elemMatch: {          
        'startDate': {
            $gte: startDate,
            $lt: endDate
        },          
        'endDate': {
            $gte: startDate,
            $lt: endDate
        },
        isBusy: true
      }
    }
})

这将返回给用户_id : ObjectId("5b6495b4611de4551f5eb8d4"),如果您仔细查看代码提供的日期和两个日期范围,这是正确的结果。该用户 is busy 在 2017-11-23 和 2018-09-23 期间,因为他确实有一个 Shooting 事件 2018-01-23 到 2018-08-23 ("_id" : ObjectId("5b6493b5611de4551f5eb878"))。到目前为止,一切都很好。现在让我们添加$not

db.getCollection('busy').find({
  "user.busy": {
    $not: {
      $elemMatch: {          
        'startDate': {
            $gte: startDate,
            $lt: endDate
        },          
        'endDate': {
            $gte: startDate,
            $lt: endDate
        },
        isBusy: true
      }
    }
  }
})

结果是用户"_id" : ObjectId("5b6495e5611de4551f5eb8df")。这又是正确的结果,因为该用户在 2017 年 11 月 23 日和 2018 年 9 月 23 日的日期范围内没有任何事件。

结论...您的查询有效! :)

【讨论】:

  • 你在 mongo 上试过吗?我在想这可能是 Mongoose 中的某个操作员或其他东西的问题。因为它在我的实现中不起作用...
  • 我在 Mongo/Robo 3T 控制台中测试它。
  • 这可能与猫鼬有关,我在主帖上添加信息。
  • 您是否尝试仅使用$elemMatch 而不使用$not 来查看它是否有效?确保至少返回您期望的文档。
  • @soulpaul 所以我最终只用一个模型等做了一个小应用程序。使用猫鼬一切都按预期工作。对于示例数据,我使用了上面发布的 2 个模型,因为它是 very 明确的,什么时候可用,什么时候不可用,取决于过去的日期。我使用与上面提出的相同日期作为测试范围。
猜你喜欢
  • 2015-09-28
  • 2020-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多