Setzen Sie einfach ein $addToSet
Operator kann nicht für Sie arbeiten, da Ihre Daten kein echter "Satz"
sind per Definition eine Sammlung von "völlig unterschiedlichen" Objekten.
Der andere Teil des logischen Sinns hier ist, dass Sie an den Daten arbeiten würden, sobald sie ankommen, entweder als einzelnes Objekt oder als Feed. Ich gehe davon aus, dass es sich um einen Feed mit vielen Elementen in irgendeiner Form handelt und dass Sie eine Art Stream-Prozessor verwenden können, um zu dieser Struktur pro empfangenem Dokument zu gelangen:
{
"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
}
Konvertieren in ein Standard-Dezimalformat sowie ein UTC-Datum, da alle Gebietsschemaeinstellungen wirklich die Domäne Ihrer Anwendung sein sollten, sobald Daten natürlich aus dem Datenspeicher abgerufen werden.
Ich würde auch Ihr "intraDayQuoteSchema" zumindest ein wenig glätten, indem ich den Verweis auf die andere Sammlung entferne und nur die Daten dort einfüge. Sie würden immer noch eine Suche beim Einfügen benötigen, aber der Overhead des zusätzlichen Auffüllens beim Lesen scheint teurer zu sein als der Speicher-Overhead:
intradayQuotesSchema = Schema({
symbol:{
name: String,
code: String
},
day:Date,
quotes:[quotesSchema]
});
Das hängt von Ihrem Nutzungsverhalten ab, aber so ist es wahrscheinlich effektiver.
Der Rest hängt wirklich davon ab, was für
akzeptabel iststream.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) {
}
);
}
);
}
);
});
});
Wenn Sie das geänderte Dokument in der Antwort nicht wirklich benötigen, würden Sie einige Vorteile daraus ziehen, wenn Sie die Bulk Operations API hier implementieren und alle Aktualisierungen in diesem Paket innerhalb einer einzigen Datenbankanforderung senden:
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
});
});
});
Der Punkt ist, dass nur eine der Anweisungen dort tatsächlich Daten ändert, und da dies alles in derselben Anfrage gesendet wird, gibt es weniger Hin und Her zwischen Anwendung und Server.
Der alternative Fall ist, dass es in diesem Fall möglicherweise einfacher ist, die tatsächlichen Daten in einer anderen Sammlung zu referenzieren. Dies wird dann zu einer einfachen Angelegenheit der Verarbeitung von 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) {
}
);
}
}
);
});
});
Es kommt wirklich darauf an, wie wichtig es für Sie ist, die Daten für Angebote innerhalb des „Tages“-Dokuments zu verschachteln. Der Hauptunterschied besteht darin, ob Sie diese Dokumente basierend auf den Daten einiger dieser "Anführungszeichen"-Felder abfragen oder anderweitig mit dem Aufwand der Verwendung von .populate()
leben möchten um die "Zitate" aus der anderen Sammlung zu ziehen.
Wenn referenziert wird und die Kursdaten für Ihre Abfragefilterung wichtig sind, können Sie diese Sammlung natürlich immer nur nach der _id
abfragen Werte, die übereinstimmen und einen $in
Abfrage auf den "Tag"-Dokumenten, um nur Tage abzugleichen, die diese übereinstimmenden "Quote"-Dokumente enthalten.
Es ist eine große Entscheidung, wo es am wichtigsten ist, welchen Weg Sie einschlagen, je nachdem, wie Ihre Anwendung die Daten verwendet. Hoffentlich sollte dies Sie zu den allgemeinen Konzepten führen, die dahinterstehen, was Sie erreichen möchten.
P.S. Wenn Sie nicht "sicher" sind, dass Ihre Quelldaten immer ein Datum sind, das auf eine genaue "Minute" gerundet ist, möchten Sie wahrscheinlich die gleiche Art von Datumsrundungsmathematik verwenden, die auch verwendet wird, um den diskreten "Tag" zu erhalten.