MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Mongoose trovane uno e spingilo su una serie di documenti

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.