MongoDB / Mongoose-запит на певну дату?


141

Чи можливий запит на певну дату?

У кулінарній книзі mongo я виявив, що ми можемо це зробити для діапазону Запит для діапазону дат :

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

Але чи можлива конкретна дата? Це не працює:

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

Відповіді:


212

Це має спрацювати, якщо дати, збережені у БД, не мають часу (лише рік, місяць, день).

Цілком ймовірно, що збережені вами дати new Date(), що включають компоненти часу. Для запитів у ті часи потрібно створити діапазон дат, який включає всі моменти в день.

db.posts.find( //query today up to tonight
  {"created_on": {"$gte": new Date(2012, 7, 14), "$lt": new Date(2012, 7, 15)}})

29
Пам’ятайте, що у функції Date () аргумент місяця починається відлік від 0, а не 1. З іншого боку, дні починають рахуватись з 1 ... подробиці
Марк Стосберг

Хіба не краще зробити 1 день, щоб отримати наступну дату, а не жорсткий код обох?
raju

2
Чи добре працює цей метод, якщо дата зберігається приблизно так: >> "дата": ISODate ("2016-01-04T14: 07: 17.496Z")
santhosh

У вас немає переключень на місяці та дати. Формат дат повинен бути: yyyy, dd, MM
thethakuri

123

... Через 5 років я наполегливо пропоную використовувати замість цього дата-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.


13
Я пропоную використовувати .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 Явне клонування, а не неявне, такий же результат, але, можливо, легше читати!
П’єр-Люк Джендро

1
З іншого боку , я міг би запропонувати наступне для $lt: moment(today).endOf('day'). Щоб запобігти включенню фактичних результатів наступного дня.
greduan

1
для мене moment(today).endOf('day')дає один і той же день з моменту: 23:59:59.999. Тому насправді правильніше використовувати $lte, інакше об’єкти в цей конкретний час будуть ігноровані.
leonprou

11

Так, об’єкт Date завершує дату і час, тому порівняти його з просто значенням дати не працює.

Ви можете просто використовувати $, де оператор виражає більш складні умови за допомогою булевого вираження Javascript :)

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

created_onє полем дати і 2012-07-14є вказаною датою.

Дата повинна бути точно у форматі РРРР-ММ-DD .

Примітка. Використовуйте $whereщадно, це має наслідки для продуктивності.


10

Ти намагався:

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

Проблема, з якою ви збираєтеся зіткнутися, полягає в тому, що дати зберігаються як часові позначки в Монго. Отже, щоб відповідати даті, ви просите її відповідати часовій позначці. У вашому випадку я думаю, що ви намагаєтесь відповідати день (тобто з 00:00 до 23:59 на певну дату). Якщо ваші дати зберігаються без разів, то у вас повинно бути добре. В іншому випадку спробуйте вказати дату як проміжок часу в той самий день (тобто. Start = 00: 00, end = 23: 59), якщо gte не працює.

подібне питання


1
Це стосуватиметься всіх елементів, молодших за вказану дату, що, мабуть, не те, чого хотів ОП. Подумайте про додавання параметра "lt", як і інші відповіді.
BenSower

Я думаю, якби у вас $gteзамість gteцього було б краще.
пустий джек

На це вже відповіли правильніше вище, але мені було неприємно знати, що моя відповідь вимкнена, тому я оновив її, щоб вона відповіла правильним. Гей, минуло 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. Я думав, що я додам спосіб вирішення проблеми для довідки.

У нас є колекція під назвою "дані" з числовим полем "значення" та полем дати "дата". У нас був процес, який ми вважали безсильним, але в результаті додавали 2 х значення на день під час другого запуску:

{ "_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")}

Нам потрібно лише 1 з 2 записів, тому довелося вдатися до javascript, щоб очистити db. Наш початковий підхід полягав у тому, щоб повторити результати та видалити будь-яке поле з часом між 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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.