mongoose 如何在mongoDB中用0值填充缺失的文档?

7dl7o3gd  于 2023-01-05  发布在  Go
关注(0)|答案(3)|浏览(178)

我有一个集合,其中存储了某一天的配水量。现在,在设备未运行的某些天,数据不会存储在数据库中,我也不会在集合中获取数据。例如,我查询过去7天的配水量,而设备仅运行了两天,结果如下:

[{ 
    "uID" : "12345678", 
    "midNightTimeStamp" : NumberInt(1645381800), 
    "waterDispensed" : NumberInt(53)
},
{ 
    "uID" : "12345678", 
    "midNightTimeStamp" : NumberInt(1645641000), 
    "waterDispensed" : NumberInt(30)
}]

转换上述两个时间戳后,我得到了2月21日星期一和2月24日星期四的数据。现在,如果我运行2月21日到2月27日的查询,如下所示:

db.getCollection("analytics").find({ uID: "12345678", midNightTimeStamp: {"$in": [1645381800, 1645468200, 1645554600, 1645641000, 1645727400, 1645813800, 1645900200]}})

这只返回以上两个文档,如何填充midNightTimeStamp的缺失值,以获得不存在的文档列表:

[{ 
    "uID" : "12345678", 
    "midNightTimeStamp" : 1645381800, 
    "waterDispensed" : 53
},
{ 
    "uID" : "12345678", 
    "midNightTimeStamp" : 1645468200, 
    "waterDispensed" : 0
},
{ 
    "uID" : "12345678", 
    "midNightTimeStamp" : 1645554600, 
    "waterDispensed" : 0
},
{ 
    "uID" : "12345678", 
    "midNightTimeStamp" : 1645641000, 
    "waterDispensed" : 30
},
{ 
    "uID" : "12345678", 
    "midNightTimeStamp" : 1645727400, 
    "waterDispensed" : 0
},
{ 
    "uID" : "12345678", 
    "midNightTimeStamp" : 1645813800, 
    "waterDispensed" : 0
},
{
    "uID" : "12345678", 
    "midNightTimeStamp" : 1645900200, 
    "waterDispensed" : 0
}
m1m5dgzv

m1m5dgzv1#

也许是这样的:

db.collection.aggregate([
{
 $group: {
   _id: null,
   ar: {
    $push: "$$ROOT"
   },
   mind: {
    "$min": "$midNightTimeStamp"
   },
   maxd: {
    "$max": "$midNightTimeStamp"
   }
  }
 },
 {
  $project: {
  ar: {
    $map: {
      input: {
        $range: [
          "$mind",
          {
            "$sum": [
              "$maxd",
              86400
            ]
          },
          86400
        ]
      },
      as: "dateInRange",
      in: {
        $let: {
          vars: {
            dateIndex: {
              "$indexOfArray": [
                "$ar.midNightTimeStamp",
                "$$dateInRange"
              ]
            }
          },
          in: {
            $cond: {
              if: {
                $ne: [
                  "$$dateIndex",
                  -1
                ]
              },
              then: {
                $arrayElemAt: [
                  "$ar",
                  "$$dateIndex"
                ]
              },
              else: {
                midNightTimeStamp: "$$dateInRange",
                "waterDispensed": NumberInt(0)
              }
            }
          }
        }
       }
      }
     }
    }
  },
  {
   $unwind: "$ar"
  },
  {
   $project: {
    _id: 0,
    "waterDispensed": "$ar.waterDispensed",
    midNightTimeStamp: "$ar.midNightTimeStamp",
    "Date": {
      $toDate: {
         "$multiply": [
         "$ar.midNightTimeStamp",
         1000
       ]
      }
    }
   }
  }
])

解释道:
1.$分组文档以查找时间戳的最大值和最小值,$将所有元素推入名为“ar”的临时数组
1.$投影数组$Map,生成日期范围为最大值和最小值,步长为1x天(86400),用waterDispanced填充空元素:0
1.$展开数组$ar
1.$在最终输出中只投影我们需要的字段。
playground

qeeaahzv

qeeaahzv2#

这与另一个答案有一点不同,它只需要抓住所需的"uID"。MQL中的注解解释了这个过程。

db.collection.aggregate([
  { // The uID we want
    "$match": { "uID": "12345678" }
  },
  { // grab all the uID docs as "water"
    // keep uID
    "$group": {
      "_id": null,
      "water": { "$push": "$$CURRENT" },
      "uID": { "$first": "$uID" }
    }
  },
  { // create outArray
    "$set": {
      "outArray": {
        // by mapping time vals
        "$map": {
          "input": {
            "$range": [ NumberInt(1645381800), NumberInt(1645900200), 86400 ]
          },
          "in": {
            "$cond": [
              { // already have doc?
                "$in": [ "$$this", "$water.midNightTimeStamp" ]
              },
              { // yes!  Get it!
                "$arrayElemAt": [
                  "$water",
                  { "$indexOfArray": [ "$water.midNightTimeStamp", "$$this" ] }
                ]
              },
              { // no, create it
                "uID": "$uID",
                "midNightTimeStamp": "$$this",
                "waterDispensed": 0
              }
            ]
          }
        }
      }
    }
  },
  { // only need outArray now
    "$project": {
      "_id": 0,
      "outArray": 1
    }
  },
  { // create docs
    "$unwind": "$outArray"
  },
  { // hoist them
    "$replaceWith": "$outArray"
  },
  { // don't need _id
    "$unset": "_id"
  }
])

mongoplayground.net上试试。

r1zk6ea1

r1zk6ea13#

从MongoDB5.1开始,您可以使用$densify聚合操作符用平均值或默认值填充缺失的时间序列数据。
https://www.mongodb.com/docs/rapid/reference/operator/aggregation/densify/
在您的情况下,可能需要在聚合时将时间戳字段转换为日期,以便可以使用$densify
您还可以在MongoDB World 2022上观看this presentation$densify的快速解释。

相关问题