从多个阵列返回最新排序日期

时间:2016-04-18 17:16:43

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

我目前有这个架构

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"来搜索模式。然后只从#34;传感器","执行器"中选择最后一个对象(按日期)。和"状态"阵列,但我无法弄清楚如何做到这一点。

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

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

提前感谢您提供任何帮助

1 个答案:

答案 0 :(得分:1)

这里最好的建议是" store"首先排序的数组。有可能他们可能已经在考虑任何$push操作(或者即使您使用.push())实际上只是"追加"到数组,以便最新项目是"最后"反正。

所以除非你真的"改变"创建后的"date"属性,然后是"最新日期" 总是" last"项目无论如何。在这种情况下,仅$slice条目:

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

]);

"如果",某些原因你实际上设法以不同的方式存储或更改了"date"属性,以便最新的不再是" last",那么将所有未来更新与$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处理,最后使用$group处理$first来有效地从排序数组中获取单个项目。

你需要这样做" per"数组,因为$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执行操作最后一项是一个非常简单的过程。