【问题标题】:Return Latest Sorted Date from Multiple Arrays从多个数组返回最新的排序日期
【发布时间】:2016-08-10 13:36:33
【问题描述】:

我目前有这个架构

var dataSchema = new Schema({
hid: { type: String },
sensors: [{
    nid: { type: String },
    sid: { type: String },
    data: {
        param1: { type: String },
        param2: { type: String },
        data: { type: String }
    },
    date: { type: Date, default: Date.now }
}],
actuators: [{
    nid: { type: String },
    aid: { type: String },
    control_id: { type: String },
    data: {
        param1: { type: String },
        param2: { type: String },
        data: { type: String }
    },
    date: { type: Date, default: Date.now }
}],
status: [{
    nid: {type: String},
    status_code: {type: String},
    date: { type: Date, default: Date.now }
}],
updated: { type: Date, default: Date.now },
created: { type: Date }
});

我正在尝试构建的查询应该通过“隐藏”搜索架构,然后只从“传感器”、“执行器”和“状态”数组中选择最后一个对象(按日期),但我可以'不知道该怎么做。

通过这个查询,我可以部分实现我想要得到的结果,但它一次只给我一个数组,所以我必须查询数据库 3 次,我会避免这样做

db.getCollection('data').aggregate([
                    { $match : { hid : "testhid" } },
                    {$project : {"sensors" : 1}},
                    {$unwind : "$sensors"},
                    {$sort : {"sensors.date" : -1}},
                    {$limit : 1}
                ])

提前感谢您的帮助

【问题讨论】:

  • 能否请您发布示例数据(测试文档)
  • 您是否不仅要按传感器日期排序,还要按其他日期排序?您可以多次展开,但不能一次展开多个数组。这应该在一个查询中起作用。

标签: javascript mongodb mongoose mongodb-query aggregation-framework


【解决方案1】:

这里最好的建议是首先“存储”已排序的数组。很有可能他们可能已经在考虑任何 $push 操作(或者即使您使用了 .push() )实际上只会“附加”到数组中,因此最新的项目无论如何都是“最后一个”。

因此,除非您在创建后实际“更改”"date" 属性,否则“最新日期”始终始终是“最后一个”项目。在这种情况下,只需$slice 条目:

Data.find({ "hid": "testhid" }).select({
    "sensors": { "$slice": -1 },
    "actuators": { "$slice": -1 },
    "status": { "$slice": -1 }
}).exec(function(err,data) {

]);

“如果”,出于某种原因,您实际上确实设法以不同的方式存储或更改了 "date" 属性,因此它们最新的不再是“最后的”,那么让所有未来的更新都使用$sort 修饰符与 $push。这可以“确保”对数组的添加进行一致排序。您甚至可以在一个简单的语句中修改整个集合:

Date.update(
    {},
    {
      "$push": {
          "sensors": { "$each": [], "$sort": { "date": 1 } },
          "actuators": { "$each": [], "$sort": { "date": 1 } },
          "status": { "$each": [], "$sort": { "date": 1 } }
      }
    },
    { "multi": true },
    function(err,num) {

    }
)

在该语句中,集合中的每个文档都将提到的每个数组重新排序为“最新日期”是每个数组的“最后一个”条目。这意味着$slice 的上述用法完全没问题。


现在“如果”,对于您的情况,这绝对不可能,并且您实际上有一些理由为什么不将数组条目通常存储在"date" 顺序中,那么(并且只有那么)您应该求助于使用.aggregate() 得到结果:

Data.aggregate(
 [
   { "$match": { "hid": "testhid" } },
   { "$unwind": "$sensors" },
   { "$sort": { "_id": 1, "sensors.date": -1 } },
   { "$group": {
       "_id": "$_id",
       "sensors": { "$first": "$sensors" },
       "actuators": { "$first": "$actuators" },
       "status": { "$first": "$status" },
       "updated": { "$first": "$updated" },
       "created": { "$first": "$created" }
   }},
   { "$unwind": "$actuators" },
   { "$sort": { "_id": 1, "actuators.date": -1 } },
   { "$group": {
       "_id": "$_id",
       "sensors": { "$first": "$sensors" },
       "actuators": { "$first": "$actuators" },
       "status": { "$first": "$status" },
       "updated": { "$first": "$updated" },
       "created": { "$first": "$created" }
   }},
   { "$unwind": "$status" },
   { "$sort": { "_id": 1, "status.date": -1 } },
   { "$group": {
       "_id": "$_id",
       "sensors": { "$first": "$sensors" },
       "actuators": { "$first": "$actuators" },
       "status": { "$first": "$status" },
       "updated": { "$first": "$updated" },
       "created": { "$first": "$created" }
   }}
 ],
 function(err,data) {

 }
)

现实情况是,MongoDB 无法在任何查询或聚合管道语句的返回中“内联排序”数组内容。您只能通过使用$unwind 处理,然后使用$sort,最后使用$first 处理$group 来有效地从排序数组中获取单个项目。

您需要执行“每个”数组,因为$unwind 的过程正在为每个数组项创建单独的文档。您“可以”一口气完成所有操作,例如:

Data.aggregate(
 [
   { "$match": { "hid": "testhid" } },
   { "$unwind": "$sensors" },
   { "$unwind": "$actuators" },
   { "$unwind": "$status" }
   { "$sort": { 
       "_id": 1, 
       "sensors.date": -1,
       "actuators.date": -1,
       "actuators.status": -1
   }},
   { "$group": {
       "_id": "$_id",
       "sensors": { "$first": "$sensors" },
       "actuators": { "$first": "$actuators" },
       "status": { "$first": "$status" },
       "updated": { "$first": "$updated" },
       "created": { "$first": "$created" }
   }}
 ],
 function(err,data) {

 }
)

但考虑到所有因素,它对其他流程的改进并没有那么大。


这里真正的课应该是“保持数组排序”然后对$slice最后一项进行操作是一个非常简单的过程。 p>

【讨论】:

  • 非常感谢您的完整回答
  • 最后一个问题,有没有办法在切片sensors 数组时也包含$elemMatch: { nid: "1"}?我试过这个"sensors": [{$elemMatch: { nid: "1"}}, {"$slice": -10 }],,但它不起作用。再次感谢您的帮助。
  • @danielebuso 这需要聚合框架。无论如何,投影不可能匹配超过 1 个数组元素。但是使用聚合框架有一种更简单的方法。 但是这是另一个问题,应该单独提出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-16
  • 1970-01-01
相关资源
最近更新 更多