sql >> Database >  >> NoSQL >> MongoDB

Mongoose vindt er een en duwt naar een reeks documenten

Plaats in feite een $addToSet operator kan niet voor u werken omdat uw gegevens geen echte "set" zijn per definitie een verzameling van "volledig verschillende" objecten zijn.

Het andere logische gevoel hier is dat u aan de gegevens zou werken zodra deze binnenkomen, hetzij als een enkel object of als een feed. Ik neem aan dat het een feed is van veel items in een of andere vorm en dat je een soort streamprocessor kunt gebruiken om tot deze structuur per ontvangen document te komen:

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

Converteren naar een standaard decimaal formaat en een UTC-datum, aangezien eventuele landinstellingen eigenlijk het domein van uw toepassing zouden moeten zijn zodra de gegevens uit de datastore zijn opgehaald natuurlijk.

Ik zou ook op zijn minst je "intraDayQuoteSchema" een beetje afvlakken door de verwijzing naar de andere verzameling te verwijderen en de gegevens daar gewoon in te plaatsen. Je zou nog steeds een zoekopdracht nodig hebben bij het invoegen, maar de overhead van de extra populatie bij het lezen lijkt duurder te zijn dan de opslagoverhead:

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

Het hangt af van je gebruikspatronen, maar het is op die manier waarschijnlijk effectiever.

De rest komt echt neer op wat acceptabel is voor

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

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

Als u het gewijzigde document in het antwoord niet echt nodig hebt, zou u enig voordeel hebben door de Bulk Operations API hier te implementeren en alle updates in dit pakket binnen één databaseverzoek te verzenden:

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

Het punt is dat slechts één van de instructies daar daadwerkelijk gegevens zal wijzigen, en aangezien dit allemaal in hetzelfde verzoek wordt verzonden, is er minder heen en weer tussen de applicatie en de server.

Het alternatieve geval is dat het in dit geval misschien eenvoudiger is om de werkelijke gegevens in een andere verzameling te laten verwijzen. Dit wordt dan gewoon een kwestie van upserts verwerken:

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

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

Het komt er echt op neer hoe belangrijk het voor u is om de gegevens voor aanhalingstekens genest in het "dag" -document te hebben. Het belangrijkste onderscheid is dat als u die documenten wilt opvragen op basis van de gegevens van een aantal van die "aanhalingstekens"-velden of anderszins wilt leven met de overhead van het gebruik van .populate() om de "citaten" uit de andere verzameling binnen te halen.

Als ernaar wordt verwezen en de offertegegevens belangrijk zijn voor het filteren van uw zoekopdracht, dan kunt u natuurlijk altijd die verzameling opvragen voor de _id waarden die overeenkomen met en gebruik maken van een $in query op de "dag"-documenten om alleen dagen te matchen die die overeenkomende "quote"-documenten bevatten.

Het is een grote beslissing waarbij het er het meest toe doet welk pad u neemt op basis van hoe uw toepassing de gegevens gebruikt. Hopelijk zou dit je moeten helpen bij de algemene concepten achter doen wat je wilt bereiken.

P.S. Tenzij u er "zeker" van bent dat uw brongegevens altijd een datum zijn die is afgerond op een exacte "minuut", dan wilt u waarschijnlijk dezelfde soort datumafronding gebruiken die ook werd gebruikt om de discrete "dag" te krijgen.




  1. Maakt de Rentalis Redis-bibliotheek zijn eigen thread voor asynchrone callbacks?

  2. Hoe MongoDB Java-stuurprogramma MongoOptions configureren voor productiegebruik?

  3. Time-out StackExchange.Redis

  4. Is het ok om de mongo ObjectId in een string te veranderen en deze voor URL's te gebruiken?