MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Mongoose znajdź jeden i przejdź do szeregu dokumentów

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ń”.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Aktualizacja zbiorcza za pomocą Mongoose

  2. Jak zaktualizować, jeśli istnieje, w przeciwnym razie wstawić nowy dokument?

  3. Przeszukaj wszystkie kolekcje Mongo i wykonaj zapytanie

  4. Przewracanie się w Mongo DB i problem z Id

  5. Node.js i MongoDB, ponowne wykorzystanie obiektu DB