Về cơ bản, hãy đặt một $ addToSet
toán tử không thể làm việc cho bạn vì dữ liệu của bạn không phải là "bộ"
đúng theo định nghĩa là một tập hợp các đối tượng "hoàn toàn khác biệt".
Phần logic khác ở đây là bạn sẽ làm việc trên dữ liệu khi nó đến, dưới dạng một đối tượng sinlge hoặc một nguồn cấp dữ liệu. Tôi sẽ cho rằng nó là một nguồn cấp dữ liệu của nhiều mục ở một số dạng và bạn có thể sử dụng một số loại trình xử lý luồng để đi đến cấu trúc này cho mỗi tài liệu nhận được:
{
"date": new Date("2015-03-09 13:23:00.000Z"),
"symbol": "AAPL",
"open": 127.14
"high": 127.17,
"low": 127.12
"close": 127.15,
"volume": 19734
}
Chuyển đổi sang định dạng thập phân tiêu chuẩn cũng như ngày UTC vì bất kỳ cài đặt ngôn ngữ nào thực sự phải là miền của ứng dụng của bạn sau khi dữ liệu được truy xuất từ kho dữ liệu.
Ít nhất tôi cũng sẽ làm phẳng "intraDayQuoteSchema" của bạn một chút bằng cách xóa tham chiếu đến bộ sưu tập khác và chỉ đưa dữ liệu vào đó. Bạn vẫn cần tra cứu về phần chèn, nhưng chi phí của phần điền bổ sung khi đọc có vẻ tốn kém hơn tổng chi phí lưu trữ:
intradayQuotesSchema = Schema({
symbol:{
name: String,
code: String
},
day:Date,
quotes:[quotesSchema]
});
Nó phụ thuộc vào cách sử dụng của bạn, nhưng nó có thể hiệu quả hơn theo cách đó.
Phần còn lại thực sự là những gì có thể chấp nhận được
stream.on(function(data) {
var symbol = data.symbol,
myDay = new Date(
data.date.valueOf() -
( data.date.valueOf() % 1000 * 60 * 60 * 24 ));
delete data.symbol;
symbol.findOne({ "code": symbol },function(err,stock) {
intraDayQuote.findOneAndUpdate(
{ "symbol.code": symbol , "day": myDay },
{ "$setOnInsert": {
"symbol.name": stock.name
"quotes": [data]
}},
{ "upsert": true }
function(err,doc) {
intraDayQuote.findOneAndUpdate(
{
"symbol.code": symbol,
"day": myDay,
"quotes.date": data.date
},
{ "$set": { "quotes.$": data } },
function(err,doc) {
intraDayQuote.findOneAndUpdate(
{
"symbol.code": symbol,
"day": myDay,
"quotes.date": { "$ne": data.date }
},
{ "$push": { "quotes": data } },
function(err,doc) {
}
);
}
);
}
);
});
});
Nếu bạn không thực sự cần tài liệu đã sửa đổi trong phản hồi thì bạn sẽ nhận được một số lợi ích bằng cách triển khai API hoạt động hàng loạt tại đây và gửi tất cả các bản cập nhật trong gói này trong một yêu cầu cơ sở dữ liệu duy nhất:
stream.on("data",function(data) {
var symbol = data.symbol,
myDay = new Date(
data.date.valueOf() -
( data.date.valueOf() % 1000 * 60 * 60 * 24 ));
delete data.symbol;
symbol.findOne({ "code": symbol },function(err,stock) {
var bulk = intraDayQuote.collection.initializeOrderedBulkOp();
bulk.find({ "symbol.code": symbol , "day": myDay })
.upsert().updateOne({
"$setOnInsert": {
"symbol.name": stock.name
"quotes": [data]
}
});
bulk.find({
"symbol.code": symbol,
"day": myDay,
"quotes.date": data.date
}).updateOne({
"$set": { "quotes.$": data }
});
bulk.find({
"symbol.code": symbol,
"day": myDay,
"quotes.date": { "$ne": data.date }
}).updateOne({
"$push": { "quotes": data }
});
bulk.execute(function(err,result) {
// maybe do something with the response
});
});
});
Vấn đề là chỉ một trong các câu lệnh ở đó sẽ thực sự sửa đổi dữ liệu và vì tất cả điều này được gửi theo cùng một yêu cầu nên ít qua lại giữa ứng dụng và máy chủ hơn.
Trường hợp thay thế là nó có thể đơn giản hơn trong trường hợp này để dữ liệu thực tế được tham chiếu trong một bộ sưu tập khác. Điều này sau đó chỉ trở thành một vấn đề đơn giản của việc xử lý các cảnh báo:
intradayQuotesSchema = Schema({
symbol:{
name: String,
code: String
},
day:Date,
quotes:[{ type: Schema.Types.ObjectId, ref: "quote" }]
});
// and in the steam processor
stream.on("data",function(data) {
var symbol = data.symbol,
myDay = new Date(
data.date.valueOf() -
( data.date.valueOf() % 1000 * 60 * 60 * 24 ));
delete data.symbol;
symbol.findOne({ "code": symbol },function(err,stock) {
quote.update(
{ "date": data.date },
{ "$setOnInsert": data },
{ "upsert": true },
function(err,num,raw) {
if ( !raw.updatedExisting ) {
intraDayQuote.update(
{ "symbol.code": symbol , "day": myDay },
{
"$setOnInsert": {
"symbol.name": stock.name
},
"$addToSet": { "quotes": data }
},
{ "upsert": true },
function(err,num,raw) {
}
);
}
}
);
});
});
Việc có dữ liệu cho các dấu ngoặc kép được lồng trong tài liệu "ngày" thực sự quan trọng đối với bạn như thế nào. Sự khác biệt chính là nếu bạn muốn truy vấn các tài liệu đó dựa trên dữ liệu, một số trường "trích dẫn" đó hoặc sống với chi phí sử dụng .populate ()
để lấy "dấu ngoặc kép" từ bộ sưu tập khác.
Tất nhiên nếu được tham chiếu và dữ liệu trích dẫn quan trọng đối với việc lọc truy vấn của bạn, thì bạn luôn có thể truy vấn bộ sưu tập đó cho _id
các giá trị phù hợp và sử dụng $ in
truy vấn trên các tài liệu "ngày" để chỉ khớp với các ngày có chứa các tài liệu "báo giá" phù hợp đó.
Đó là một quyết định lớn, quan trọng nhất là bạn chọn con đường nào dựa trên cách ứng dụng của bạn sử dụng dữ liệu. Hy vọng rằng điều này sẽ hướng dẫn bạn về các khái niệm chung đằng sau việc làm những gì bạn muốn đạt được.
P.S Trừ khi bạn "chắc chắn" rằng dữ liệu nguồn của bạn luôn là ngày được làm tròn chính xác đến "phút", thì bạn có thể muốn sử dụng cùng một loại toán làm tròn ngày như được sử dụng để có được "ngày" rời rạc.