MongoDB / Mongoose запрашивает определенную дату?

145

Можно ли запросить конкретную дату?

Я нашел в кулинарной книге mongo, что мы можем сделать это для диапазона, запрашивая диапазон дат , например:

db.posts.find({"created_on": {"$gte": start, "$lt": end}})

Но возможно ли это на конкретную дату? Это не работает:

db.posts.find({"created_on": new Date(2012, 7, 14) })
Unitech
источник

Ответы:

222

Это должно работать, если даты, которые вы сохранили в БД, указаны без времени (только год, месяц, день).

Скорее всего, это были сохраненные вами даты new Date(), включая компоненты времени. Чтобы запросить это время, вам нужно создать диапазон дат, включающий все моменты дня.

db.posts.find( //query today up to tonight
  {"created_on": {"$gte": new Date(2012, 7, 14), "$lt": new Date(2012, 7, 15)}})
Rdrey
источник
31
Помните, что в функции Date () аргумент месяца начинает отсчет с 0, а не с 1. С другой стороны, дни начинают отсчет с 1 ... подробнее
Марк Стосберг,
Разве не лучше сделать _ 1 день, чтобы получить следующую дату, чем жестко запрограммировать их обоих?
raju
2
Этот метод работает нормально, если дата хранится следующим образом: >> "date": ISODate ("2016-01-04T14: 07: 17.496Z")
santhosh
Разве у вас нет переключателей месяцев и даты. Формат даты должен быть: гггг, дд, ММ
тетакури
131

... 5+ лет спустя я настоятельно рекомендую вместо этого использовать date-fns

import endOfDayfrom 'date-fns/endOfDay'
import startOfDay from 'date-fns/startOfDay'

MyModel.find({
  createdAt: {
    $gte: startOfDay(new Date()),
    $lte: endOfDay(new Date())
  }
})

Для тех из нас, кто использует Moment.js

const moment = require('moment')

const today = moment().startOf('day')

MyModel.find({
  createdAt: {
    $gte: today.toDate(),
    $lte: moment(today).endOf('day').toDate()
  }
})

Важно: все моменты изменчивы !

tomorrow = today.add(1, 'days')не работает, так как также мутирует today. Вызов moment(today)решает эту проблему путем неявного клонирования today.

Пьер-Люк Жендро
источник
14
Я предлагаю использовать .startOf('day')вместо .hours (0) .minutes (0) .seconds (0). Итак, первая строка будет такой:var today = moment().startOf('day')
Джим Гёртс
2
Если мы используем moment(today)для клонирования объекта, другое решение:var tomorrow = today.clone().add(1, 'days')
johntellsall
1
@johntellsall Явное клонирование, а не неявное, результат тот же, но, возможно, его действительно легче читать!
Pier-Luc Gendreau
1
С другой стороны , я мог бы предложить следующее для $lt: moment(today).endOf('day'). Чтобы предотвратить включение фактических результатов на следующий день.
greduan
1
для меня moment(today).endOf('day')дает один и тот же день с момента: 23:59:59.999. Так что на самом деле выглядит более правильным в использовании $lte, иначе объекты в этот конкретный момент будут проигнорированы.
leonprou
11

Да, объект Date дополняет дату и время, поэтому сравнение его только со значением даты не работает.

Вы можете просто использовать оператор $ where, чтобы выразить более сложное условие с помощью логического выражения Javascript :)

db.posts.find({ '$where': 'this.created_on.toJSON().slice(0, 10) == "2012-07-14"' })

created_on- это поле даты и времени, и 2012-07-14это указанная дата.

Дата должна быть точно в формате ГГГГ-ММ-ДД .

Примечание: используйте $whereэкономно, это сказывается на производительности.

Фейсал Хаснайн
источник
10

Попытался ли ты:

db.posts.find({"created_on": {"$gte": new Date(2012, 7, 14), "$lt": new Date(2012, 7, 15)}})

Проблема, с которой вы столкнетесь, заключается в том, что даты хранятся в Mongo как метки времени. Итак, чтобы сопоставить дату, вы просите ее сопоставить метку времени. В вашем случае я думаю, что вы пытаетесь сопоставить день (например, с 00:00 до 23:59 в определенную дату). Если ваши даты хранятся без времени, все должно быть в порядке. В противном случае попробуйте указать дату как диапазон времени в тот же день (например, start = 00:00, end = 23:59), если gte не работает.

аналогичный вопрос

Майкл Д Джонсон
источник
1
Это будет включать все элементы моложе указанной даты, что, вероятно, не то, что хотел OP. Подумайте о добавлении опции «lt», как и другие ответы.
BenSower
Я думаю , что если у вас есть $gteвместо gteнего будет лучше.
jack blank
На этот вопрос уже был дан более правильный ответ выше, но меня беспокоило то, что я знал, что мой ответ был неверным, поэтому я обновил его, чтобы он соответствовал вопросу. Эй, прошло 4 года. lol
Майкл Д Джонсон
6

Вы можете использовать следующий подход для метода API, чтобы получить результаты за определенный день:

# [HTTP GET]
getMeals: (req, res) ->
  options = {}
  # eg. api/v1/meals?date=Tue+Jan+13+2015+00%3A00%3A00+GMT%2B0100+(CET)
  if req.query.date?
    date = new Date req.query.date
    date.setHours 0, 0, 0, 0
    endDate = new Date date
    endDate.setHours 23, 59, 59, 59
    options.date =
      $lt: endDate
      $gte: date

  Meal.find options, (err, meals) ->
      if err or not meals
        handleError err, meals, res
      else
        res.json createJSON meals, null, 'meals'
Даниэль Кмак
источник
1

У нас была проблема, связанная с дублированием данных в нашей базе данных, с полем даты, имеющим несколько значений, где мы должны были иметь 1. Я подумал, что добавлю способ решения проблемы для справки.

У нас есть коллекция под названием «данные» с числовым полем «значение» и полем «дата». У нас был процесс, который мы считали идемпотентным, но в итоге при втором запуске добавлялись два значения в день:

{ "_id" : "1", "type":"x", "value":1.23, date : ISODate("2013-05-21T08:00:00Z")}
{ "_id" : "2", "type":"x", "value":1.23, date : ISODate("2013-05-21T17:00:00Z")}

Нам нужна только одна из двух записей, поэтому пришлось прибегнуть к javascript для очистки базы данных. Наш первоначальный подход заключался в переборе результатов и удалении любого поля со временем между 6 и 11 часами утра (все дубликаты были утром), но во время реализации внесены изменения. Вот сценарий, используемый для его исправления:

var data = db.data.find({"type" : "x"})
var found = [];
while (data.hasNext()){
    var datum = data.next();
    var rdate = datum.date;
    // instead of the next set of conditions, we could have just used rdate.getHour() and checked if it was in the morning, but this approach was slightly better...
    if (typeof found[rdate.getDate()+"-"+rdate.getMonth() + "-" + rdate.getFullYear()] !== "undefined") {
       if (datum.value != found[rdate.getDate()+"-"+rdate.getMonth() + "-" + rdate.getFullYear()]) {
           print("DISCREPENCY!!!: " + datum._id + " for date " + datum.date);
       }
       else {
           print("Removing " + datum._id);
           db.data.remove({ "_id": datum._id});
       }
    }
    else {
       found[rdate.getDate()+"-"+rdate.getMonth() + "-" + rdate.getFullYear()] = datum.value;
    }
}

а затем запустил его с mongo thedatabase fixer_script.js

Бретт
источник