从多个数组中返回最近排序的日期

Return Latest Sorted Date from Multiple Arrays

本文关键字:最近 排序 日期 返回 数组      更新时间:2023-09-26

我目前有这个模式

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 }
});

我试图构建的查询应该通过"hid"搜索模式,然后只从"传感器"、"执行器"answers"状态"数组中选择最后一个对象(按日期),但我不知道如何做到这一点。

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

db.getCollection('data').aggregate([
                    { $match : { hid : "testhid" } },
                    {$project : {"sensors" : 1}},
                    {$unwind : "$sensors"},
                    {$sort : {"sensors.date" : -1}},
                    {$limit : 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执行操作——最后一项是一个非常简单的过程。