Mongo查询以按时间参数每天获取1个文档

时间:2019-10-24 19:17:20

标签: mongodb datetime

我无法从数据库中获取所需日期的文档。

我的数据库结构是这样的:

{
  date: 2019-10-24T10:00:00.000Z,
  value: 6
},
{
  date: 2019-10-24T10:01:03.000Z,
  value: 6
},
{
  date: 2019-10-24T10:02:35.000Z,
  value: 6
},
...

并尝试获取带有2个参数的查询:

  • startDate(结束日期-x天)
  • endDate

并且每天在startDate和endDate之间传送1个文档,此文档的时间(HH:mm:ss)需要最接近endDate之一。 像这样:

start = new Date('2019-10-22T10:00:00.000Z')
end = new Date('2019-10-24T10:00:00.000Z)

{
  date: '2019-10-22T09:59:13.000Z',
  value: 10
},
{
  date: '2019-10-23T10:00:00.000Z',
  value: 17
},
{
  date: '2019-10-24T09:58:55.000Z',
  value: 10
}

现在,我拥有此汇总函数,可以获取每天的第一份文档:

.aggregate([
    {
      $match: {
        date: { $gte: ISODate('2019-05-26T12:00:00.000Z'), $lte: ISODate('2019-10-26T12:00:00.000Z') }
      }
    },
    {
      $project: {
        _id: 1,
        value: 1,
        docDate: '$date',
        day: {
          '$dayOfMonth': '$date'
        },
        month: {
          '$month': '$date'
        },
        year: {
          '$year': '$date'
        }
      }
    },
    {
      $project: {
        _id: 1,
        value: 1,
        docDate: 1,
        date: {
          '$concat': [
            {
              $substr: ['$year', 0, 4]
            },
            '-',
            {
              $substr: ['$month', 0, 2]
            },
            '-',
            {
              $substr: ['$day', 0, 2]
            }
          ]
        }
      }
    },
    {
      $group: {
        _id: '$date',
        objId: {
          $first: '$_id'
        },
        value: {
          $first: '$value'
        },
        date: {
          $first: '$docDate'
        }
      }
    },
    {
      $project: {
        _id: '$objId',
        value: 1,
        date: 1
      }
    },
    {
      '$sort': {
        date: 1
      }
    }
  ]
)

2 个答案:

答案 0 :(得分:2)

所以我认为这个查询可能就是您要寻找的...

const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();
const port = process.env.PORT || 80;
const server = process.env.SERVER || 'pa-dev-1.flanderscapital.com';
const bodyParser = require('body-parser')

// default options
app.use(fileUpload());

// set the view engine to ejs
app.set('view engine', 'ejs');

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))

// parse application/json
app.use(bodyParser.json())

app.use(express.static(__dirname + '/public'));

var routes = require('./app/routes')(app);


app.listen(port, server, () => console.log(`PA Tools Server listening on port ${port}!`))

// Get image of GAEA logo
var publicDir = require('path').join(__dirname, 'public');
app.use(express.static(publicDir));

管道策略的分解:

  1. $ match-按日期范围选择要考虑的记录范围

  2. $ addFields-仅获取日期字符串而不带时间。这是$ group实际分组所必需的。如果字符串中也包含时间,则无法正确分组

  3. $ sort date -1 =分组之前需要这样做,因此我们可以在$ group中使用$ first运算符

  4. $ group-汇总并使用$ first选择分组中的项目

  5. $ replaceRoot-将管道输出转回原始文档格式

  6. $ project-删除临时的date_string字段

  7. $ sort date 1-按正常排序顺序放回数据。

输出:

db.records.aggregate([
    { $match: { 
         date: { 
           $gte: ISODate('2019-05-03T12:01:07Z'), 
           $lte: ISODate('2019-05-07T12:01:07Z') 
        }
      }
    },
    { $addFields:  {
         date_string: { $dateToString: { format: "%Y-%m-%d", date: "$date" } }
       }
    },
    { $sort: { date: -1 } },
    { $group: {
        _id: "$date_string",
        my_doc: { $first: "$$ROOT" }
      }
    },
    { $replaceRoot: { newRoot: "$my_doc" } },
    { $project: { date_string: 0 } }, 
    { $sort: { date: 1 } }
])

答案 1 :(得分:1)

我找到了解决方案,我添加了分钟变量并使用它进行了匹配。还将组数据更改为$ last而不是$ first。

db.getCollection('weightedaverages').aggregate([
    {
      $match: {
        date: { $gte: ISODate('2019-05-26T15:00:00.000Z'), $lte: ISODate('2019-10-26T15:00:00.000Z') }
      }
    },
    {
      $project: {
        _id: 1,
        value: 1,
        docDate: '$date',
        day: {
          '$dayOfMonth': '$date'
        },
        month: {
          '$month': '$date'
        },
        year: {
          '$year': '$date'
        },
        minutes: {
          $add: [
            {
              $multiply: [
                {
                  '$hour': '$date'
                },
                60
              ] 
            }, 
            {
              '$minute': '$date'
            } 
          ]
        } 
      }
    },
    { $match: { 'minutes' : { $lte : ISODate('2019-10-26T13:20:00.000Z').getHours() * 60 + ISODate('2019-10-26T13:20:00.000Z').getMinutes()}}},
    {
      $project: {
        _id: 1,
        value: 1,
        docDate: 1,
        date: {
          '$concat': [
            {
              $substr: ['$year', 0, 4]
            },
            '-',
            {
              $substr: ['$month', 0, 2]
            },
            '-',
            {
              $substr: ['$day', 0, 2]
            }
          ]
        }
      }
    },
    {
      $group: {
        _id: '$date',
        objId: {
          $last: '$_id'
        },
        value: {
          $last: '$value'
        },
        date: {
          $last: '$docDate'
        }
      }
    },
    {
      $project: {
        _id: '$objId',
        value: 1,
        date: 1
      }
    },
    {
      '$sort': {
        date: 1
      }
    }
  ]
)

输出:

{
  "date" : ISODate("2019-08-20T15:00:13.633Z"),
  "value" : 10
},
{
  "date" : ISODate("2019-08-19T15:00:19.850Z"),
  "value" : 5
},
...
{
  "date" : ISODate("2019-06-20T14:59:48.000Z"),
  "value" : 7
}