Làm cách nào để chỉ lưu trữ thời gian không có ngày trong MongoDB?

Cách chuẩn bị một đối tượng ngày Python được lưu trữ trong MongoDB và chạy các truy vấn theo ngày và phạm vi ngày

Cách tôi quản lý để chèn ngày vào MongoDB và chạy truy vấn giữa các ngày

Giới thiệu

Tôi nghĩ một trong những điều tẻ nhạt nhất trong Khoa học Máy tính là xử lý ngày giờ và múi giờ. Nếu Khoa học máy tính chỉ sắp xếp các bản ghi theo ngày hoặc truy vấn DB cho các bản ghi được tạo giữa các khoảng ngày, thì tôi sẽ tự gọi mình ra khỏi trò chơi.
Tôi đã biết rằng cách lưu trữ dấu thời gian tạo nên sự khác biệt và có thể cho phép bạn chạy đúng truy vấn hoặc mang đến cho bạn một trong những ngày đó.
Trường hợp của tôi khá đơn giản nhưng tôi mất hàng giờ để giải quyết. Chúng tôi đã có một bộ sưu tập MongoDB với dấu thời gian được lưu trữ dưới dạng Chuỗi. (sai lầm lớn đầu tiên). Hơn nữa, cấu trúc của mỗi bản ghi là một JSON lồng nhau (lỗi thứ hai) không phải là cấu trúc tốt nhất khi truy vấn tài liệu. Dễ hình dung, không dễ truy vấn.
Vì vậy, giả sử chúng ta phải lưu trữ các hành động do người dùng thực hiện và đối với mỗi hành động, chúng ta muốn lưu trữ dấu thời gian.
Định dạng dữ liệu ban đầu trông như thế nào

{
"user_email": "[email protected]",
"delivery": {
"box1": {
"97cc5e852cf44fc38fdb55dc006d1d01": {
"owner_name": "Peter Parker",
"owner_email": "[email protected]",
"registration_date": "2021-03-01T18:12:07+00:00"
}
},
"box2": {
"a7bd1e34f809410590679cd2c1172cd3": {
"owner_name": "Dylan Dog",
"owner_email": "[email protected]",
"registration_date": "2021-03-02T12:12:01+00:00"
},
"box3": {
"b787fdeb892d406196fda2ca9a15074b": {
"owner_name": "Nathan Never",
"owner_email": "[email protected]",
"registration_date": "2020-12-02T18:12:07+00:00"
}
},
"box4": {
"1f8741da011640988359fec4d47225f3": {
"owner_name": "Jerry Drake",
"owner_email": "[email protected]",
"registration_date": "2021-02-02T14:07:07+00:00"
}
}
}
}
}

Có hai vấn đề với cấu trúc trên. Đầu tiên là giá trị register_date được lưu dưới dạng Chuỗi. Nó không cho phép tôi truy vấn kết quả theo phạm vi ngày. Ngày được lưu trữ ở định dạng Chuỗi rất dễ hiển thị và giả sử ngày khớp với định dạng chuẩn, tương đối dễ chuyển đổi trở lại đối tượng ngày giờ nhưng tôi không thể chạy truy vấn như

{“registration_date”: {“$gte”: ‘2021–03–03T18:12:07+00:00’, “$lte”: ‘2021–03–02T18:12:07+00:00’}}

Vấn đề thứ hai là khá khó để truy vấn bằng ID ( e. g. 1f8741da011640988359fec4d47225f3), là khóa của mỗi từ điển lồng nhau. Về vấn đề này, bài viết này khá giải thích và giúp tôi hiểu được lỗi tôi mắc phải trong thiết kế dữ liệu ban đầu

Tái cấu trúc dữ liệu để theo cách của MongoDB

Sau khi xem qua tài liệu về MongoDB, tôi nhận ra rằng cách lưu trữ dấu thời gian phù hợp là loại Ngày JavaScript. Giai đoạn = Stage

Như đã báo cáo trong chính thức ,

MongoDB không có đối tượng ngày giờ đặc biệt và nó sử dụng loại Ngày của JavaScript, được lưu trữ ở dạng. Bên trong, các đối tượng được lưu trữ dưới dạng số nguyên 64 bit đã ký biểu thị số mili giây kể từ kỷ nguyên Unix (ngày 1 tháng 1 năm 1970). Đề cập đến loại Ngày BSON là ngày giờ UTC. BSON Loại ngày được ký. Các giá trị âm biểu thị các ngày trước năm 1970

Date() trả về ngày hiện tại dưới dạng một chuỗi trong vỏ mongo

new Date() trả về ngày hiện tại dưới dạng một đối tượng. Shell mongo bao bọc đối tượng bằng trình trợ giúp ISODate. ISODate là trong UTC

MongoDB tự động gói ngày với chức năng. ISODate(). ISODate() là một hàm tích hợp bao bọc đối tượng Ngày JavaScript gốc, cung cấp một cách thuận tiện để biểu thị ngày ở định dạng con người có thể đọc được, duy trì việc sử dụng đầy đủ truy vấn ngày và lập chỉ mục

Vì vậy, ngoài hộp, MongoDB cung cấp một đại diện ISO mặc định cho các ngày. Nếu bạn cần một định dạng khác với định dạng ISO, bạn cần tự chuyển đổi ở phía máy khách

Hoàn hảo. Vì vậy, trước tiên tôi quyết định sửa đổi loại khóa register_date thành datetime chỉ để nhận ra rằng, với cấu trúc dữ liệu ban đầu của mình, không thể chỉ lấy lại các bản ghi phù hợp với tiêu chí truy vấn của tôi. Đó là một cấu trúc lồng nhau, vì vậy tất cả các cấu trúc đã được trả lại. Sau đó, tôi quyết định sửa đổi cấu trúc và làm cho nó đơn giản hơn. Nhiều bản ghi hơn để lưu trữ, nhưng dễ truy vấn hơn

Để chèn ngày đăng ký dưới dạng ngày giờ Python, tôi đã sử dụng hàm datetime.today()

payload_to_insert = {  
"user_email": "[email protected]",
"owner_name": "Peter Parker"
"owner_email": "[email protected]",
"box_id" : "a7bd1e34f809410590679cd2c1172cd3",
"registration_date": datetime.today().replace(microsecond=0)

}

register_date bây giờ là một đối tượng datetime, nó được lưu trữ dưới dạng JavaScript Date type bởi MongoDB và sau đó nó tương thích với những gì MongoDB yêu cầu để chạy các truy vấn về ngày tháng

Hơn nữa, ID từng là khóa bây giờ là giá trị của một thuộc tính. Tôi đã sửa cấu trúc dữ liệu và giúp truy vấn dễ dàng

Để kiểm tra kỹ, chúng ta có thể chạy một truy vấn từ MongoDB shell để thấy rằng định dạng của register_date là Date()

db.test.find()
{ "_id" : ObjectId("..."), "registration_date" : new Date("2021-03-02T14:51:15+0000") }

Bây giờ, hãy chơi với Python và hàm datetime để chạy một vài truy vấn

Truy vấn theo phạm vi ngày

Có lẽ là một trong những truy vấn phổ biến nhất từ ​​trước đến nay, “hãy cho tôi biết tất cả kết quả giữa hai ngày trên lịch”. Đó là lý do tại sao các thành phần như thế này https. //nguyên liệu. góc cạnh. io/thành phần/datepicker/ví dụ tồn tại

Chúng tôi đã học được bài học của mình và chúng tôi biết rằng chúng tôi cần các đối tượng ngày giờ. Vì vậy, trước tiên hãy chuyển đổi một chuỗi thành một ngày giờ và sau đó tạo truy vấn của chúng tôi

from datetime import datetime, timedeltafrom_date = datetime.strptime(from_date, '%Y-%m-%d')
to_date = datetime.strptime(to_date, '%Y-%m-%d')
criteria = {"$and": [{"registration_date": {"$gte": from_date, "$lte": to_date}}, {"owner_email": "[email protected]"}]}

sau đó chúng ta có thể sử dụng các tiêu chí trong find() của mình

import json
from pymongo import MongoClient
from bson.json_util import dumps
from datetime import datetime, timezone
from datetime import timedelta


def query_by_range_of_dates(mongo_url, db_name, collection_name, owner_email, from_date,
to_date):
client = MongoClient(mongo_url)
db_instance = client[db_name]

from_date = datetime.strptime(from_date, '%Y-%m-%d')
to_date = datetime.strptime(to_date, '%Y-%m-%d')

criteria = {"$and": [{"registration_date": {"$gte": from_date, "$lte": to_date}}, {"owner_email": owner_email}]}

return json.loads(dumps(db_instance[collection_name].find(criteria)))
Truy vấn theo một ngày cụ thể

Nếu tôi muốn tất cả các hành động được thực hiện vào một ngày nhất định thì sao? . 00 đến 23. 59. 59 cùng ngày

from datetime import datetime, timedeltafrom_date_str = day_to_query + "T00:00:00+00:00"
to_date_str = day_to_query + "T23:59:59+00:00"
from_date = datetime.strptime(from_date_str, '%Y-%m-%dT%H:%M:%S%z')
to_date = datetime.strptime(to_date_str, '%Y-%m-%dT%H:%M:%S%z')
criteria = {"$and": [{"registration_date": {"$gte": from_date, "$lte": to_date}}, {"owner_email": "[email protected]"}]}

N. B. Tôi cần chỉ định múi giờ UTC vì theo mặc định, MongoDB lưu trữ các đối tượng Date() dưới dạng ISOFormat()

Truy vấn với timedelta

Một cách hữu ích khác để truy vấn ngày là quay lại từ một số ngày nhất định

from datetime import datetime, timedeltatoday = datetime.today()
days_back = today - timedelta(days=30)
criteria = {"$and": [{"registration_date": {"$gte": days_back}}, {"owner_email": [email protected]}]}
Tóm lại

MongoDB ngày có thể gây ra một số thất vọng khi đến ngày để lưu trữ và truy vấn. Ngoài ra, cấu trúc dữ liệu lồng nhau không phải là người bạn tốt nhất của chúng tôi khi chúng tôi cần truy vấn nó. Tôi đã học được rằng không phải lúc nào đơn giản cũng dễ dàng. Lưu trữ một ngày dưới dạng Chuỗi đơn giản và dễ hình dung. Tuy nhiên, nó không dễ dàng hơn để truy vấn

Làm cách nào để lưu trữ thời gian không có ngày trong MongoDB?

MongoDB không hỗ trợ ngày không có định dạng múi giờ. Cách khác để lưu trữ ngày không có múi giờ là sử dụng hai loại biểu diễn nhật ký . Đầu tiên là mili giây và thứ hai là (

Làm cách nào để lưu trữ thời gian trong MongoDB?

MongoDB lưu trữ thời gian ở dạng UTC theo mặc định và sẽ chuyển đổi bất kỳ biểu thị giờ địa phương nào sang dạng này. Các ứng dụng phải vận hành hoặc báo cáo về một số giá trị thời gian địa phương chưa sửa đổi có thể lưu trữ múi giờ cùng với dấu thời gian UTC và tính toán thời gian địa phương ban đầu trong logic ứng dụng của chúng.

Làm thế nào để chỉ lưu trữ thời gian trong cầy mangut?

Giải pháp tốt nhất mà tôi có thể đưa ra là chỉ thêm thời gian trong quá trình chèn vào cơ sở dữ liệu chứ không phải khi tạo lược đồ. Bằng cách này bạn có thể sử dụng datetime. toLocaleTimeString(); . js để chỉ thêm thời gian mà không có ngày, v.v.

Kiểu dữ liệu cho thời gian trong MongoDB là gì?

Cách được đề xuất để lưu trữ ngày tháng trong MongoDB là sử dụng kiểu dữ liệu BSON Date . Đặc tả BSON đề cập đến loại Ngày là ngày giờ UTC và là số nguyên 64 bit. Nó đại diện cho số mili giây kể từ kỷ nguyên Unix, là 00. 00. 00 UTC ngày 1 tháng 1 năm 1970.