Fondamentalmente inserisci un $addToSet
operatore non può funzionare per te perché i tuoi dati non sono un vero "set"
essendo per definizione una raccolta di oggetti "completamente distinti".
L'altro senso logico qui è che lavoreresti sui dati non appena arrivano, sia come oggetto singolo che come feed. Presumo che sia un feed di molti elementi in qualche forma e che tu possa utilizzare una sorta di stream processor per arrivare a questa struttura per documento ricevuto:
{
"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
}
Conversione in un formato decimale standard e in una data UTC poiché qualsiasi impostazione locale dovrebbe davvero essere il dominio della tua applicazione una volta recuperati i dati dal datastore, ovviamente.
Vorrei anche appiattire un po 'il tuo "intraDayQuoteSchema" rimuovendo il riferimento all'altra raccolta e inserendo semplicemente i dati lì. Avresti comunque bisogno di una ricerca all'inserimento, ma il sovraccarico del popolamento aggiuntivo in lettura sembrerebbe più costoso del sovraccarico di archiviazione:
intradayQuotesSchema = Schema({
symbol:{
name: String,
code: String
},
day:Date,
quotes:[quotesSchema]
});
Dipende dai tuoi modelli di utilizzo, ma è probabile che sia più efficace in questo modo.
Il resto si riduce davvero a ciò che è accettabile per
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) {
}
);
}
);
}
);
});
});
Se non hai effettivamente bisogno del documento modificato nella risposta, otterresti qualche vantaggio implementando qui l'API per le operazioni in blocco e inviando tutti gli aggiornamenti in questo pacchetto all'interno di una singola richiesta di database:
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
});
});
});
Il punto è che solo una delle istruzioni lì modificherà effettivamente i dati, e poiché tutto questo viene inviato nella stessa richiesta, c'è meno avanti e indietro tra l'applicazione e il server.
Il caso alternativo è che in questo caso potrebbe essere più semplice avere i dati effettivi referenziati in un'altra raccolta. Questo diventa quindi solo una semplice questione di elaborazione degli upsert:
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) {
}
);
}
}
);
});
});
Dipende davvero da quanto sia importante per te avere i dati per le citazioni annidati all'interno del documento "giorno". La distinzione principale è se vuoi interrogare quei documenti in base ai dati di alcuni di quei campi "virgolette" o altrimenti vivere con il sovraccarico dell'utilizzo di .populate()
per inserire le "virgolette" dall'altra raccolta.
Ovviamente, se referenziato e i dati del preventivo sono importanti per il filtraggio delle query, puoi sempre interrogare quella raccolta per il _id
valori che corrispondono e utilizzano un $in
query sui documenti "giorno" per abbinare solo i giorni che contengono quei documenti "virgolette" abbinati.
È una decisione importante in cui conta di più il percorso che prendi in base al modo in cui la tua applicazione utilizza i dati. Si spera che questo dovrebbe guidarti sui concetti generali alla base del fare ciò che vuoi ottenere.
P.S. A meno che tu non sia "sicuro" che i tuoi dati di origine siano sempre una data arrotondata a un "minuto" esatto, probabilmente vorrai utilizzare lo stesso tipo di matematica di arrotondamento della data usata per ottenere anche il "giorno" discreto.