sql >> Base de Datos >  >> NoSQL >> MongoDB

Mongoose encuentra uno y empuja a una variedad de documentos

Básicamente, coloque un $addToSet El operador no puede funcionar para usted porque sus datos no son un verdadero "set" siendo por definición una colección de objetos "completamente distintos".

La otra pieza de sentido lógico aquí es que estaría trabajando en los datos a medida que llegan, ya sea como un objeto único o como una fuente. Supongo que es una fuente de muchos elementos de alguna forma y que puede usar algún tipo de procesador de flujo para llegar a esta estructura por documento recibido:

{
    "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
}

Convirtiendo a un formato decimal estándar, así como a una fecha UTC, ya que cualquier configuración local realmente debería ser el dominio de su aplicación una vez que los datos se recuperan del almacén de datos, por supuesto.

También al menos aplanaría un poco su "intraDayQuoteSchema" eliminando la referencia a la otra colección y simplemente poniendo los datos allí. Todavía necesitaría una búsqueda en la inserción, pero la sobrecarga de la población adicional en la lectura parecería ser más costosa que la sobrecarga de almacenamiento:

intradayQuotesSchema = Schema({
    symbol:{
        name: String,
        code: String
    },
    day:Date,
    quotes:[quotesSchema]
});

Depende de sus patrones de uso, pero es probable que sea más efectivo de esa manera.

El resto realmente se reduce a lo que es aceptable para

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) {

                            }
                       );    
                    }
                );
            }
        );    
    });
});

Si en realidad no necesita el documento modificado en la respuesta, obtendrá algún beneficio al implementar la API de operaciones masivas aquí y enviar todas las actualizaciones en este paquete dentro de una sola solicitud de base de datos:

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
         });            
     });
});

El punto es que solo una de las declaraciones modificará realmente los datos, y dado que todo se envía en la misma solicitud, hay menos ida y vuelta entre la aplicación y el servidor.

El caso alternativo es que podría ser más simple en este caso hacer referencia a los datos reales en otra colección. Entonces esto se convierte en una simple cuestión de procesar 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) {

                        }
                    );
                }
            }
        );
    });
});

Realmente se reduce a cuán importante es para usted tener los datos de las cotizaciones anidadas dentro del documento "día". La distinción principal es si desea consultar esos documentos en función de los datos de algunos de esos campos de "comillas" o vivir con la sobrecarga de usar .populate() para extraer las "comillas" de la otra colección.

Por supuesto, si se hace referencia a ellos y los datos de la cotización son importantes para el filtrado de consultas, siempre puede consultar esa colección para el _id valores que coinciden y usan un $in consulta en los documentos de "día" para hacer coincidir solo los días que contienen esos documentos de "presupuesto" coincidentes.

Es una gran decisión en la que más importa qué ruta tomar en función de cómo su aplicación utiliza los datos. Con suerte, esto debería guiarlo sobre los conceptos generales detrás de hacer lo que quiere lograr.

PD A menos que esté "seguro" de que sus datos de origen siempre son una fecha redondeada a un "minuto" exacto, entonces probablemente desee emplear el mismo tipo de matemáticas de redondeo de fecha que se usa para obtener el "día" discreto también.