Zasadniczo umieść $addToSet
operator nie może pracować dla Ciebie, ponieważ Twoje dane nie są prawdziwym "zestawem"
z definicji jest zbiorem „całkowicie odrębnych” obiektów.
Innym logicznym sensem jest to, że pracujesz nad danymi, gdy nadchodzą, jako pojedynczy obiekt lub kanał. Zakładam, że jest to kanał zawierający wiele elementów w jakiejś formie i że możesz użyć jakiegoś procesora strumieniowego, aby uzyskać tę strukturę dla każdego otrzymanego dokumentu:
{
"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
}
Konwersja do standardowego formatu dziesiętnego, a także daty UTC, ponieważ wszelkie ustawienia regionalne naprawdę powinny być domeną Twojej aplikacji, oczywiście po pobraniu danych z magazynu danych.
Przynajmniej nieco spłaszczyłbym twój „intraDayQuoteSchema”, usuwając odniesienie do innej kolekcji i po prostu umieszczając tam dane. Nadal będziesz potrzebować wyszukiwania przy wstawianiu, ale dodatkowe obciążenie przy odczycie wydaje się być droższe niż obciążenie pamięci masowej:
intradayQuotesSchema = Schema({
symbol:{
name: String,
code: String
},
day:Date,
quotes:[quotesSchema]
});
Zależy to od Twoich wzorców użytkowania, ale w ten sposób prawdopodobnie będzie to bardziej skuteczne.
Reszta naprawdę sprowadza się do tego, co jest do zaakceptowania
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) {
}
);
}
);
}
);
});
});
Jeśli tak naprawdę nie potrzebujesz zmodyfikowanego dokumentu w odpowiedzi, możesz uzyskać pewne korzyści, implementując tutaj interfejs API Bulk Operations i wysyłając wszystkie aktualizacje z tego pakietu w ramach jednego żądania bazy danych:
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
});
});
});
Chodzi o to, że tylko jedna z tych instrukcji faktycznie zmodyfikuje dane, a ponieważ wszystkie są wysyłane w tym samym żądaniu, między aplikacją a serwerem jest mniej tam iz powrotem.
Alternatywnym przypadkiem jest to, że w tym przypadku może być po prostu prostsze, aby rzeczywiste dane były przywoływane w innej kolekcji. To staje się po prostu kwestią przetwarzania 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) {
}
);
}
}
);
});
});
To naprawdę sprowadza się do tego, jak ważne jest dla Ciebie, aby dane dotyczące cytatów były zagnieżdżone w dokumencie „dzień”. Główną różnicą jest to, czy chcesz wysyłać zapytania do tych dokumentów na podstawie danych niektórych z tych pól „cytat” lub w inny sposób żyć z obciążeniem związanym z użyciem .populate()
aby pobrać „cytaty” z innej kolekcji.
Oczywiście, jeśli istnieje odwołanie, a dane cytatu są ważne dla filtrowania zapytania, zawsze możesz po prostu wysłać zapytanie do tej kolekcji dla _id
wartości, które pasują i używają $in
zapytaj o dokumenty „dnia”, aby dopasować tylko te dni, które zawierają te dopasowane dokumenty „cytat”.
To poważna decyzja, w której najważniejsze jest, którą ścieżką wybierzesz w oparciu o sposób, w jaki Twoja aplikacja wykorzystuje dane. Mam nadzieję, że powinno to doprowadzić Cię do ogólnych koncepcji dotyczących robienia tego, co chcesz osiągnąć.
PS O ile nie jesteś „pewny”, że dane źródłowe są zawsze datą zaokrągloną do dokładnej „minuty”, prawdopodobnie chcesz zastosować ten sam rodzaj matematyki zaokrąglania dat, który jest używany do uzyskania dyskretnego „dzień”.