Grundlæggende skal du sætte en $addToSet
operatør kan ikke arbejde for dig, fordi dine data ikke er et sandt "sæt"
per definition er en samling af "helt adskilte" objekter.
Den anden logiske mening her er, at du ville arbejde på dataene, når de ankommer, enten som et enkelt objekt eller et feed. Jeg antager, at det er et feed med mange elementer i en eller anden form, og at du kan bruge en slags stream-processor til at nå frem til denne struktur pr. modtaget dokument:
{
"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
}
Konvertering til et standard decimalformat samt en UTC-dato, da alle lokalitetsindstillinger virkelig burde være domænet for din applikation, når først data er hentet fra datalageret, selvfølgelig.
Jeg ville også i det mindste flade dit "intraDayQuoteSchema" lidt ud ved at fjerne henvisningen til den anden samling og bare lægge data derind. Du vil stadig have brug for et opslag ved indsættelse, men overhead for den ekstra indfyldning ved læsning ser ud til at være dyrere end lageroverhead:
intradayQuotesSchema = Schema({
symbol:{
name: String,
code: String
},
day:Date,
quotes:[quotesSchema]
});
Det afhænger af dine brugsmønstre, men det vil sandsynligvis være mere effektivt på den måde.
Resten kommer virkelig ned til, hvad der er acceptabelt for
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) {
}
);
}
);
}
);
});
});
Hvis du faktisk ikke har brug for det ændrede dokument i svaret, vil du få en vis fordel ved at implementere Bulk Operations API her og sende alle opdateringer i denne pakke inden for en enkelt databaseanmodning:
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
});
});
});
Pointen er, at kun et af udsagn der faktisk vil ændre data, og da det hele sendes i samme anmodning, er der mindre frem og tilbage mellem applikationen og serveren.
Det alternative tilfælde er, at det måske bare er mere enkelt i dette tilfælde at få de faktiske data refereret i en anden samling. Dette bliver så bare et simpelt spørgsmål om at behandle 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) {
}
);
}
}
);
});
});
Det kommer virkelig ned på, hvor vigtigt det er for dig at have data for citater indlejret i "dag"-dokumentet. Den vigtigste forskel er, hvis du ønsker at forespørge på disse dokumenter baseret på data, nogle af disse "citat"-felter eller på anden måde leve med overhead ved at bruge .populate()
at trække "citater" fra den anden samling ind.
Selvfølgelig, hvis der henvises til, og tilbudsdataene er vigtige for din forespørgselsfiltrering, kan du altid bare forespørge på denne samling for _id
værdier, der matcher og bruger en $in
forespørg på "dag"-dokumenterne for kun at matche dage, der indeholder de matchede "citat"-dokumenter.
Det er en stor beslutning, hvor det betyder mest, hvilken vej du tager baseret på, hvordan din applikation bruger dataene. Forhåbentlig bør dette guide dig til de generelle koncepter bag at gøre det, du ønsker at opnå.
P.S. Medmindre du er "sikker på", at dine kildedata altid er en dato afrundet til et nøjagtigt "minut", så vil du sandsynligvis også bruge den samme form for datoafrundingsmatematik, som bruges til også at få den diskrete "dag".