По принцип поставете $addToSet
операторът не може да работи за вас, защото вашите данни не са истински "set"
по дефиниция е колекция от "напълно различни" обекти.
Другата част от логическия смисъл тук е, че ще работите върху данните, когато пристигнат, или като отделен обект, или като канал. Предполагам, че това е емисия от много елементи под някаква форма и че можете да използвате някакъв вид поточен процесор, за да стигнете до тази структура за всеки получен документ:
{
"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
}
Преобразуване в стандартен десетичен формат, както и UTC дата, тъй като всички локални настройки наистина трябва да бъдат домейнът на вашето приложение, след като данните бъдат извлечени от хранилището за данни, разбира се.
Също така бих поне малко изравнил вашата "intraDayQuoteSchema", като премахна препратката към другата колекция и просто поставих данните там. Все още ще имате нужда от търсене при вмъкване, но режийните разходи за допълнително попълване при четене изглеждат по-скъпи от режийните разходи за съхранение:
intradayQuotesSchema = Schema({
symbol:{
name: String,
code: String
},
day:Date,
quotes:[quotesSchema]
});
Зависи от вашите модели на използване, но вероятно ще бъде по-ефективно по този начин.
Останалото наистина се свежда до това какво е приемливо за
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) {
}
);
}
);
}
);
});
});
Ако всъщност не се нуждаете от модифицирания документ в отговора, тогава ще получите известна полза, като внедрите API за групови операции тук и изпратите всички актуализации в този пакет в рамките на една заявка за база данни:
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
});
});
});
Въпросът е, че само един от изразите там действително ще промени данните и тъй като всичко това се изпраща в една и съща заявка, има по-малко движение напред-назад между приложението и сървъра.
Алтернативният случай е, че може просто да е по-просто в този случай действителните данни да са посочени в друга колекция. Тогава това става просто въпрос на обработка на upserts:
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) {
}
);
}
}
);
});
});
Наистина се свежда до това колко важно е за вас данните за котировките да са вложени в документа „ден“. Основното разграничение е, ако искате да направите заявка за тези документи въз основа на данните, някои от тези полета за "кавички" или по друг начин да живеете с режийните разходи за използване на .populate()
за да изтеглите „кавичките“ от другата колекция.
Разбира се, ако има препратки и данните за офертата са важни за филтрирането на вашата заявка, тогава винаги можете просто да поискате тази колекция за _id
стойности, които съвпадат и използват $inкод>
заявка в документите „ден“, за да съпоставите само дни, които съдържат тези съответстващи документи „цитат“.
Това е голямо решение, когато е от най-голямо значение кой път ще поемете въз основа на това как вашето приложение използва данните. Надяваме се, че това трябва да ви насочи към общите концепции зад това, което искате да постигнете.
P.S. Освен ако не сте „сигурни“, че вашите изходни данни винаги са дата, закръглена до точна „минута“, тогава вероятно искате да използвате същия вид математика за закръгляване на дата, която се използва, за да получите и дискретния „ден“.