Lägg i princip en $addToSet
operatören kan inte fungera för dig eftersom din data inte är en sann "uppsättning"
per definition är en samling av "helt distinkta" objekt.
Den andra logiska känslan här är att du skulle arbeta med data när den anländer, antingen som ett enda objekt eller en feed. Jag antar att det är ett flöde av många objekt i någon form och att du kan använda någon form av strömprocessor för att komma fram till denna struktur per mottagna 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 till ett standarddecimalformat såväl som ett UTC-datum eftersom alla språkinställningar verkligen borde vara domänen för din applikation när data hämtas från datalagret såklart.
Jag skulle också åtminstone platta ut ditt "intraDayQuoteSchema" lite genom att ta bort referensen till den andra samlingen och bara lägga in datan där. Du skulle fortfarande behöva en sökning vid infogning, men overheaden för den extra populationen vid läsning verkar vara dyrare än lagringsoverheaden:
intradayQuotesSchema = Schema({
symbol:{
name: String,
code: String
},
day:Date,
quotes:[quotesSchema]
});
Det beror på dina användningsmönster, men det är sannolikt mer effektivt på det sättet.
Resten handlar egentligen om vad som är acceptabelt för
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) {
}
);
}
);
}
);
});
});
Om du faktiskt inte behöver det modifierade dokumentet i svaret skulle du få en viss fördel genom att implementera Bulk Operations API här och skicka alla uppdateringar i detta paket inom en enda databasförfrågan:
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
});
});
});
Poängen är att endast ett av påståendena där faktiskt kommer att modifiera data, och eftersom allt detta skickas i samma begäran är det mindre fram och tillbaka mellan applikationen och servern.
Det alternativa fallet är att det kanske bara är enklare i det här fallet att ha de faktiska uppgifterna refererade i en annan samling. Detta blir då bara en enkel fråga om att bearbeta 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 handlar verkligen om hur viktigt det är för dig att ha data för citat kapslade i "dag"-dokumentet. Den huvudsakliga skillnaden är om du vill fråga dessa dokument baserat på data några av dessa "citat"-fält eller på annat sätt leva med omkostnaden för att använda .populate()
att dra in "citaten" från den andra samlingen.
Om det hänvisas till och offertdata är viktiga för din frågefiltrering, kan du naturligtvis alltid fråga den samlingen för _id
värden som matchar och använder en $in
fråga på "dag"-dokumenten för att bara matcha dagar som innehåller de matchade "citat"-dokumenten.
Det är ett stort beslut där det spelar störst roll vilken väg du tar baserat på hur din applikation använder datan. Förhoppningsvis bör detta vägleda dig om de allmänna koncepten bakom att göra det du vill uppnå.
P.S. Om du inte är "säker på" att din källdata alltid är ett datum avrundat till en exakt "minut" så vill du förmodligen använda samma typ av datumavrundningsmatematik som används för att få den diskreta "dagen" också.