MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

MongoDB:Рамка за агрегиране:Вземете документ с последна дата за идентификатор на групиране

За да отговорите директно на вашия въпрос, да, това е най-ефективният начин. Но мисля, че трябва да изясним защо това е така.

Както беше предложено в алтернативите, единственото нещо, което хората гледат, е "сортиране" на резултатите ви, преди да преминат към $group етап и това, което те гледат, е стойността на "timestamp", така че бихте искали да сте сигурни, че всичко е в ред "timestamp", така че оттук и формата:

db.temperature.aggregate([
    { "$sort": { "station": 1, "dt": -1 } },
    { "$group": {
        "_id": "$station", 
        "result": { "$first":"$dt"}, "t": {"$first":"$t"} 
    }}
])

И както беше посочено, разбира се, ще искате индекс, който да отразява това, за да направите сортирането ефективно:

Въпреки това, и това е истинската точка. Това, което изглежда е било пренебрегнато от другите (ако не е така за себе си), е, че всички тези данни вероятно са вмъкнати вече във времеви ред, така че всяко отчитане се записва като добавено.

Така че красотата на това е _id поле ( с ObjectId по подразбиране). ) вече е в ред "timestamp", тъй като самият той всъщност съдържа времева стойност и това прави изявлението възможно:

db.temperature.aggregate([
    { "$group": {
        "_id": "$station", 
        "result": { "$last":"$dt"}, "t": {"$last":"$t"} 
    }}
])

И енат по-бързо. Защо? Е, не е нужно да избирате индекс (допълнителен код за извикване), също така не е нужно да „зареждате“ индекса в допълнение към документа.

Вече знаем, че документите са в ред (от _id ) така че $last границите са напълно валидни. Вие така или иначе сканирате всичко и бихте могли също да „разпространите“ заявка в _id стойности като еднакво валидни за между две дати.

Единственото истинско нещо, което трябва да се каже тук, е, че при използване на "реалния свят" може да е по-практично за вас да $match между диапазони от дати, когато правите този вид натрупване, за разлика от получаването на "първия" и "последния" _id стойности, за да дефинирате "диапазон" или нещо подобно във вашата действителна употреба.

И така, къде е доказателството за това? Е, сравнително лесно е да се възпроизвежда, така че току-що го направих, като генерирах някои примерни данни:

var stations = [ 
    "AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL",
    "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA",
    "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE",
    "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK",
    "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT",
    "VA", "WA", "WV", "WI", "WY"
];


for ( i=0; i<200000; i++ ) {

    var station = stations[Math.floor(Math.random()*stations.length)];
    var t = Math.floor(Math.random() * ( 96 - 50 + 1 )) +50;
    dt = new Date();

    db.temperatures.insert({
        station: station,
        t: t,
        dt: dt
    });

}

На моя хардуер (8GB лаптоп с въртящ се диск, който не е звезден, но със сигурност е достатъчен) стартирането на всяка форма на изявлението ясно показва забележима пауза с версията, използваща индекс и сортиране (същите клавиши в индекса като оператора за сортиране). Това е само малка пауза, но разликата е достатъчно значителна, за да се забележи.

Дори да погледнете изхода за обяснение (версия 2.6 и по-нова, или всъщност има в 2.4.9, макар и не документирано), можете да видите разликата в това, въпреки че $sort се оптимизира поради наличието на индекс, времето изглежда е с избор на индекс и след това зареждане на индексираните записи. Включително всички полета за „покрити“ индексната заявка не прави разлика.

Също така за запис, чистото индексиране на датата и само сортирането на стойностите на датата дава същия резултат. Вероятно малко по-бързо, но все пак по-бавно от естествената индексна форма без сортирането.

Така че стига да можете с удоволствие да „обхватите“ на първия и последно _id стойности, тогава е вярно, че използването на естествения индекс в реда за вмъкване всъщност е най-ефективният начин да направите това. Вашият реален пробег може да варира в зависимост от това дали това е практично за вас или не и може просто да се окаже по-удобно да приложите индекса и сортирането на датата.

Но ако сте доволни от използването на _id диапазони или по-големи от "последния" _id във вашата заявка, тогава може би една настройка, за да получите стойностите заедно с вашите резултати, така че всъщност да можете да съхранявате и използвате тази информация в последователни заявки:

db.temperature.aggregate([
    // Get documents "greater than" the "highest" _id value found last time
    { "$match": {
        "_id": { "$gt":  ObjectId("536076603e70a99790b7845d") }
    }},

    // Do the grouping with addition of the returned field
    { "$group": {
        "_id": "$station", 
        "result": { "$last":"$dt"},
        "t": {"$last":"$t"},
        "lastDoc": { "$last": "$_id" } 
    }}
])

И ако всъщност сте "следвали" резултатите по този начин, тогава можете да определите максималната стойност на ObjectId от вашите резултати и го използвайте в следващата заявка.

Както и да е, забавлявайте се да играете с това, но отново Да, в този случай тази заявка е най-бързият начин.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. (MongoDB Java) $push в масив

  2. 10 съвета за подобряване на сигурността на MongoDB

  3. Как се сравняват данните на Morphia, Mongo4j и Spring за MongoDB?

  4. Вземете списък с индекси в MongoDB

  5. MongoDB на Ubuntu няма да стартира като услуга, нищо в регистрационния файл