在数组中的对象内按日期搜索

时间:2018-05-15 21:17:32

标签: node.js mongodb mongoose mongodb-query

我有以下Mongoose架构:

let ExerciserSchema = new Schema({
  username: {
    type: String,
    required: true
  },
  exercises: [{
    desc: String,
    duration: Number,
    date: {
      type: Date,
      default: new Date()
    }
  }]
});

我想按用户名搜索并将练习结果限制为日期范围。

我尝试了这个查找功能:

let user = await Exerciser.find(
      { "username": name },
      { "exercises.date": { "$gte": from }},
      { "exercises.date": { "$lte": to }}
    ).exec((err, data) => {
      if (err) {
        res.json({ Error: "Data not found" })
        return done(err);
      }
      else {
        res.json(data);
        return done(null, data);
      }
    });

但是,它记录错误而不返回数据。 MongoError: Unsupported projection option: exercises.date: { $gte: new Date(1526342400000) }

我从这个错误中意识到我的日期正在以毫秒为单位进行搜索,但我console.log就在我运行上述函数之前,它处于日期模式,这就是我想要的:{ {1}}

如何才能完成这项工作,以便根据我的架构搜索日期范围?如有必要,我可以在Schema中更改日期的格式。我只想要最简单的解决方案。谢谢你的帮助。

2 个答案:

答案 0 :(得分:1)

你的查询错了。您试图写一个AND条件,但是您将文档分开而不是将所有内容放在一起。这意味着Model.find()的“第二个”参数被解释为“字段投影”,因此错误:

  

MongoError:不支持的投影选项:

所以这不是“架构问题”,而是你向Model.find()方法发送了错误的参数

对于数组中元素的多个条件,您还需要$elemMatch

// Use a try..catch block with async/await of Promises
try {
  let user = await Exerciser.find({
    "username": name,
    "exercises": {
      "$elemMatch": { "date": { "$gte": from, "$lte": to } }
    }
  });
  // work with user
} catch(e) {
  // handle any errors
}

最重要的是,你没有await回调。您await Promise就像我在这里展示的那样,或者只是传递callback。不是两个。

Exerciser.find({
  "username": name,
  "exercises": {
    "$elemMatch": { "date": { "$gte": from, "$lte": to } }
  }
}).exec((err,user) => {
   // the rest
})

仅供参考,您试图做的是:

Exerciser.find({
  "$and": [
    { "username": name },
    { "exercises.date": { "$gte": from }},
    { "exercises.date": { "$lte": to }}
  ]
)

但实际上这仍然是不正确的,因为没有$elemMatch $gte$lte适用于数组的所有元素而不仅仅是单个元素。因此,如果ANY数组项小于日期但不一定大于。

,则会显示不正确的结果

对于数组元素,$elemMatch强制执行两个条件之间的“之间”。

答案 1 :(得分:0)

我设法得到它。此答案与用户名匹配,并过滤练习,因此它们位于变量名称为tofrom的日期之间。这就是我想要的。

    let user = Exerciser.aggregate([
    { $match: { "username": id }},
    { $project: { // $project passes along the documents with the requested fields to the next stage in the pipeline
      exercises: { $filter: {
        input: "$exercises",
        as: "exercise",
        cond: { $and: [
          { $lte: [ "$$exercise.date", to ] },
          { $gte: [ "$$exercise.date", from ] },
        ]}
      }},
      username: 1, // include username in returned data
      _id: 0
    }}
  ])

结果:

[
  {
    "username": "scott",
    "exercises": [
      {
        "desc": "Situps",
        "duration": 5,
        "_id": "5af4790fd9a9c80c11aac696",
        "date": "2018-04-30T00:00:00.000Z"
      },
      {
        "desc": "Situps",
        "duration": 10,
        "_id": "5afb3f03e12e38020d059e67",
        "date": "2018-05-01T00:00:00.000Z"
      },
      {
        "desc": "Pushups",
        "duration": 8,
        "_id": "5afc08aa9259ed008e7e0895",
        "date": "2018-05-02T00:00:00.000Z"
      }
    ]
  }
]