Truy vấn MongoDB / Mongoose vào một ngày cụ thể?


141

Có thể truy vấn cho một ngày cụ thể?

Tôi đã tìm thấy trong Mongo Cookbook rằng chúng ta có thể làm điều đó cho một phạm vi Truy vấn cho Phạm vi Ngày như thế:

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

Nhưng nó có thể cho một ngày cụ thể? Điều này không hoạt động:

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

Câu trả lời:


211

Điều đó sẽ hoạt động nếu ngày bạn lưu trong DB không có thời gian (chỉ năm, tháng, ngày).

Rất có thể là ngày bạn đã lưu new Date(), bao gồm các thành phần thời gian. Để truy vấn những thời điểm đó, bạn cần tạo một phạm vi ngày bao gồm tất cả các khoảnh khắc trong một ngày.

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

29
Hãy nhớ rằng trong hàm Date (), đối số tháng bắt đầu đếm bằng 0, không phải 1. Mặt khác, ngày bắt đầu đếm ở 1 ... chi tiết
Mark Stosberg

Không phải là tốt hơn để làm _ 1 ngày để có được ngày tiếp theo chứ không phải mã cứng cả hai?
raju

2
Phương pháp này có hoạt động tốt không nếu ngày được lưu trữ như thế này: >> "ngày": ISODate ("2016-01-04T14: 07: 17.496Z")
santhosh

Bạn không có công tắc tháng và ngày của bạn. Định dạng ngày nên là: yyyy, dd, MM
thethakuri

123

... Hơn 5 năm sau, tôi thực sự khuyên bạn nên sử dụng date-fns thay thế

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

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

Đối với những người trong chúng ta sử dụng Moment.js

const moment = require('moment')

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

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

Quan trọng: tất cả các khoảnh khắc là đột biến !

tomorrow = today.add(1, 'days')không hoạt động vì nó cũng đột biến today. Gọi moment(today)giải quyết vấn đề đó bằng cách nhân bản ngầm today.


13
Tôi đề nghị sử dụng .startOf('day')thay vì .hours (0) .minutes (0) .seconds (0). Vì vậy, dòng đầu tiên sẽ là:var today = moment().startOf('day')
Jim Geurts

2
Nếu chúng ta đang sử dụng moment(today)để sao chép đối tượng, một giải pháp khác là:var tomorrow = today.clone().add(1, 'days')
johntellsall

1
@johntellsall Nhân bản vô tính chứ không phải ẩn, kết quả tương tự nhưng có lẽ dễ đọc hơn!
Cầu tàu-Luc Gendreau

1
Ngoài ra, tôi có thể đề xuất như sau cho $lt: moment(today).endOf('day'). Để ngăn chặn kết quả thực tế từ ngày hôm sau được bao gồm.
greduan

1
đối với tôi moment(today).endOf('day')đưa ra cùng ngày với thời gian : 23:59:59.999. Vì vậy, thực sự trông chính xác hơn để sử dụng $lte, nếu không các đối tượng tại thời điểm cụ thể sẽ bị bỏ qua.
leonprou

11

Vâng, đối tượng Date tuân thủ ngày và giờ, vì vậy việc so sánh nó với giá trị ngày không hoạt động.

Bạn chỉ có thể sử dụng toán tử $ where để biểu thị điều kiện phức tạp hơn với biểu thức boolean Javascript :)

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

created_onlà trường datetime và 2012-07-14là ngày được chỉ định.

Ngày phải chính xác ở định dạng YYYY-MM-DD .

Lưu ý: Sử dụng một $wherecách tiết kiệm, nó có ý nghĩa về hiệu suất.


10

Bạn đã thử chưa:

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

Vấn đề bạn sẽ gặp phải là ngày được lưu trữ dưới dạng dấu thời gian trong Mongo. Vì vậy, để khớp với một ngày bạn yêu cầu nó khớp với dấu thời gian. Trong trường hợp của bạn, tôi nghĩ rằng bạn đang cố gắng khớp một ngày (ví dụ: từ 00:00 đến 23:59 vào một ngày cụ thể). Nếu ngày của bạn được lưu trữ mà không có thời gian thì bạn sẽ ổn thôi. Mặt khác, hãy thử chỉ định ngày của bạn dưới dạng một khoảng thời gian trong cùng một ngày (ví dụ: start = 00: 00, end = 23: 59) nếu gte không hoạt động.

câu hỏi tương tự


1
Điều này sẽ bao gồm tất cả các yếu tố trẻ hơn ngày được chỉ định, có lẽ không phải là điều OP muốn. Xem xét thêm tùy chọn "lt" như các câu trả lời khác.
BenSower

Tôi nghĩ rằng nếu bạn có $gtethay vì gtenó sẽ tốt hơn.
jack trống

Điều này đã được trả lời chính xác hơn ở trên, nhưng nó đã làm tôi khó chịu khi biết rằng câu trả lời của tôi đã bị tắt, vì vậy tôi đã cập nhật nó để chính xác cho câu hỏi. Này, đã 4 năm rồi. lol
Michael D Johnson

6

Bạn có thể sử dụng phương pháp sau cho phương pháp API để nhận kết quả từ ngày cụ thể:

# [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

Chúng tôi đã có một vấn đề liên quan đến dữ liệu trùng lặp trong cơ sở dữ liệu của chúng tôi, với trường ngày có nhiều giá trị mà chúng tôi dự định có 1. Tôi nghĩ tôi đã thêm cách chúng tôi giải quyết vấn đề để tham khảo.

Chúng tôi có một bộ sưu tập gọi là "dữ liệu" với trường "giá trị" số và trường "ngày". Chúng tôi đã có một quy trình mà chúng tôi nghĩ là bình thường, nhưng cuối cùng đã thêm 2 x giá trị mỗi ngày vào lần chạy thứ hai:

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

Chúng tôi chỉ cần 1 trong 2 bản ghi, vì vậy phải sử dụng javascript để dọn sạch db. Cách tiếp cận ban đầu của chúng tôi sẽ là lặp đi lặp lại qua các kết quả và xóa bất kỳ trường nào có thời gian từ 6 giờ sáng đến 11 giờ sáng (tất cả các bản sao đều vào buổi sáng), nhưng trong quá trình thực hiện, đã thay đổi. Đây là đoạn script được sử dụng để sửa nó:

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;
    }
}

và sau đó chạy nó với mongo thedatabase fixer_script.js

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.