MongoDb Совокупный запрос, результаты группы по дням из даты ISODate [дубликат]

Строка ошибки «Ссылка на объект, не установленная на экземпляр объекта.» указывает, что вы не назначили экземпляр объекта объектной ссылке, и все же вы получаете доступ к свойствам / методам этого объекта.

например: скажем, у вас есть класс под названием myClass и он содержит одно свойство prop1.

public Class myClass
{
   public int prop1 {get;set;}
}

Теперь вы получаете доступ к этому prop1 в каком-то другом классе, как показано ниже:

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref.prop1 = 1;  //This line throws error
     }
}

выше строки выдает ошибку, потому что ссылка класса myClass объявлена, но не создана, или экземпляр объекта не назначается referecne этого класса.

Чтобы исправить это, вам нужно создать экземпляр (присвоить объект ссылке на этот класс).

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref = new myClass();
        ref.prop1 = 1;  
     }
}
43
задан Andrew Orsich 2 March 2011 в 15:49
поделиться

8 ответов

Если вы хотите, чтобы Date oject возвращался напрямую

Затем вместо применения операторов агрегации даты вместо этого применяйте «Date Math» для округления объект даты. Это часто может быть желательным, поскольку все драйверы представляют дату BSON в форме, которая обычно используется для манипуляций Date для всех языков, где это возможно:

db.datetest.aggregate([
    { "$group": {
        "_id": {
            "$add": [
                { "$subtract": [
                    { "$subtract": [ "$date", new Date(0) ] },
                    { "$mod": [
                        { "$subtract": [ "$date", new Date(0) ] },
                        1000 * 60 * 60 * 24
                    ]}
                ]},
                new Date(0)
            ]
        },
        "click": { "$sum": 1 }
    }}
])

Или, если это подразумевается в вопросе о том, что требуемый интервал группировки - это «ведра» в 15 дней, затем просто примените это к числовому значению в $mod:

db.datetest.aggregate([
    { "$group": {
        "_id": {
            "$add": [
                { "$subtract": [
                    { "$subtract": [ "$date", new Date(0) ] },
                    { "$mod": [
                        { "$subtract": [ "$date", new Date(0) ] },
                        1000 * 60 * 60 * 24 * 15
                    ]}
                ]},
                new Date(0)
            ]
        },
        "click": { "$sum": 1 }
    }}
])

Применяемая основная математика заключается в том, что когда вы $subtract два объекта Date, возвращаемый результат будет миллисекундами разного числа. Таким образом, эпоха представлена ​​Date(0) как базой для преобразования в любом конструкторе языка.

С числовым значением применяется «modulo» ( $mod ) округлить дату (вычесть остаток от деления) до требуемого интервала. Быть либо:

1000 миллисекунд x 60 секунд * 60 минут * 24 часа = 1 день

Или

1000 миллисекунды x 60 секунд * 60 минут * 24 часа * 15 дней = 15 дней

Таким образом, он является гибким для любого интервала, который вам нужен.

Точно так же, $add между «числовым» значением и объектом Date будет возвращать объект Date, эквивалентный значению millseconds для обоих объектов в сочетании (epoch равно 0, поэтому 0 плюс разница - это преобразованная дата).

Легко отображается и воспроизводится в следующем листинге:

var now = new Date();
var bulk = db.datetest.initializeOrderedBulkOp();

for ( var x = 0; x < 60; x++ ) {
    bulk.insert({ "date": new Date( now.valueOf() + ( 1000 * 60 * 60 * 24 * x ))});
}

bulk.execute();

И запуск второго примера с 15-дневными интервалами:

{ "_id" : ISODate("2016-04-14T00:00:00Z"), "click" : 12 }
{ "_id" : ISODate("2016-03-30T00:00:00Z"), "click" : 15 }
{ "_id" : ISODate("2016-03-15T00:00:00Z"), "click" : 15 }
{ "_id" : ISODate("2016-02-29T00:00:00Z"), "click" : 15 }
{ "_id" : ISODate("2016-02-14T00:00:00Z"), "click" : 3 }

Или аналогичное распределение в зависимости от текущей даты, когда выполняется листинг, и, конечно, 15-дневные интервалы будут согласованы с даты эпохи.

Использование метода «Math» немного легче настроить, особенно если вы хотите настроить периоды времени для diff в то время как вы можете аналогичным образом скорректировать цифру, добавив / вычитая числовое отличие от UTC.

0
ответ дан Blakes Seven 26 August 2018 в 21:34
поделиться

Конечно, , что является хорошим решением. Помимо этого вы можете группировать даты по дням в виде строк (как , которые отвечают ), или вы можете получить начало дат, указав поле даты (в совокупности) следующим образом:

{'$project': {
    'start_of_day': {'$subtract': [
        '$date',
        {'$add': [
            {'$multiply': [{'$hour': '$date'}, 3600000]},
            {'$multiply': [{'$minute': '$date'}, 60000]},
            {'$multiply': [{'$second': '$date'}, 1000]},
            {'$millisecond': '$date'}
        ]}
    ]},
}}

Он дает вам следующее:

{
    "start_of_day" : ISODate("2015-12-03T00:00:00.000Z")
},
{
    "start_of_day" : ISODate("2015-12-04T00:00:00.000Z")
}

У него есть несколько плюсов: вы можете манипулировать своими днями в типе даты (не числом или строкой), это позволяет использовать все операторов агрегирования даты в следующих операциях агрегации и дает вам тип даты на выходе.

0
ответ дан Community 26 August 2018 в 21:34
поделиться

Не так много работал с MongoDB, поэтому я не совсем уверен. Но разве вы не можете использовать полный Javascript? Таким образом, вы можете проанализировать свою дату с помощью класса Javascript Date, создать свою дату для дня и установить ключ в свойство «выход». И всегда добавляйте один, если ключ уже существует, иначе создайте его new со значением = 1 (первый клик). Ниже приведен код с адаптированной функцией сокращения (непроверенный код!):

db.coll.group(
{
   key:{'date':true},
   initial: {retVal: {}},
   reduce: function(doc, prev){
              var date = new Date(doc.date);
              var dateKey = date.getFullYear()+''+date.getMonth()+''+date.getDate();
              (typeof prev.retVal[dateKey] != 'undefined') ? prev.retVal[dateKey] += 1 : prev.retVal[dateKey] = 1;
            }, 
   cond: {topic:"abc"}
}
)
4
ответ дан enricog 26 August 2018 в 21:34
поделиться

Еще один поздний ответ, но все же. Поэтому, если вы хотите сделать это всего за одну итерацию и получить количество кликов, сгруппированных по дате и теме, вы можете использовать следующий код:

db.coll.group(
{
   $keyf : function(doc) {
       return { "date" : doc.date.getDate()+"/"+doc.date.getMonth()+"/"+doc.date.getFullYear(),
                "topic": doc.topic };
    },
    initial: {count:0},
    reduce: function(obj, prev) { prev.count++; }
 })

Также, если вы хотите оптимизировать запрос, как было предложено, может использовать целочисленное значение для даты (подсказка: используйте значениеOf () для ключевой даты вместо строки, хотя для моих примеров скорость была одинаковой.

Кроме того, всегда разумно проверять документы MongoDB регулярно, потому что они постоянно добавляют новые функции. Например, с новой структурой Aggregation, которая будет выпущена в версии 2.2, вы можете добиться тех же результатов гораздо проще http://docs.mongodb.org/manual / приложения / агрегация /

2
ответ дан golja 26 August 2018 в 21:34
поделиться

Это может помочь

return new Promise(function(resolve, reject) {
db.doc.aggregate(
            [
                { $match: {} },
                { $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: "$date" } }, count: { $sum: 1 } } },
                { $sort: { _id: 1 } }
            ]
        ).then(doc => {
            /* if you need a date object */
            doc.forEach(function(value, index) {
                  doc[index]._id = new Date(value._id);
              }, this);
            resolve(doc);
        }).catch(reject);
}
11
ответ дан Jonas Tomanga 26 August 2018 в 21:34
поделиться

Поздний ответ, но для записи (для всех, кто приходит на эту страницу): вам нужно использовать аргумент «keyf» вместо «key», так как ваш ключ на самом деле будет функцией дата события (т. е. «день», извлеченный с даты), а не сама дата. Это должно делать то, что вы ищете:

db.coll.group(
{
    keyf: function(doc) {
        var date = new Date(doc.date);
        var dateKey = (date.getMonth()+1)+"/"+date.getDate()+"/"+date.getFullYear()+'';
        return {'day':dateKey};
    },
    cond: {topic:"abc"},
    initial: {count:0},
    reduce: function(obj, prev) {prev.count++;}
});

. Для получения дополнительной информации взгляните на страницу документа MongoDB по агрегации и группе: http://www.mongodb.org/display / DOCS / Aggregation # Aggregation-группа

31
ответ дан mindthief 26 August 2018 в 21:34
поделиться

Новый ответ с использованием структуры агрегации Mongo

После того, как этот вопрос был задан и ответил на него, 10gen выпустил версию Mongodb версии 2.2 с базой агрегации, которая теперь является лучшим способом выполнить этот запрос. Этот запрос немного сложнее, потому что вы хотите группировать по дате, а сохраненные значения - метки времени, поэтому вам нужно что-то сделать, чтобы преобразовать метки времени в соответствующие даты. В качестве примера я просто напишу запрос, который получит правильные подсчеты.

db.col.aggregate(
   { $group: { _id: { $dayOfYear: "$date"},
               click: { $sum: 1 } } }
   )

Это вернет что-то вроде:

[
    {
        "_id" : 144,
        "click" : 165
    },
    {
        "_id" : 275,
        "click" : 12
    }
]

Вам нужно использовать $match, чтобы ограничить запрос интересующим вас диапазоном дат и $project до переименуйте _id в date. Как вы конвертируете день года назад в дату, остается как упражнение для читателя. : -)

10gen имеет удобную SQL-диаграмму преобразования агрегации Mongo Aggregation . Существует также конкретная статья о операторах агрегирования даты .

Получив немного больше внимания, вы можете использовать:

db.col.aggregate([
  { $group: {
      _id: {
        $add: [
         { $dayOfYear: "$date"}, 
         { $multiply: 
           [400, {$year: "$date"}]
         }
      ]},   
      click: { $sum: 1 },
      first: {$min: "$date"}
    }
  },
  { $sort: {_id: -1} },
  { $limit: 15 },
  { $project: { date: "$first", click: 1, _id: 0} }
])

, который поможет вам получить последние 15 дней и возвратите некоторое время в течение дня в поле date. Например:

[
    {
        "click" : 431,
        "date" : ISODate("2013-05-11T02:33:45.526Z")
    },
    {
        "click" : 702,
        "date" : ISODate("2013-05-08T02:11:00.503Z")
    },
            ...
    {
        "click" : 814,
        "date" : ISODate("2013-04-25T00:41:45.046Z")
    }
]
58
ответ дан Old Pro 26 August 2018 в 21:34
поделиться

спасибо за @mindthief, ваш ответ поможет решить мою проблему сегодня. Функция ниже может группироваться днем ​​немного легче, надежда может помочь другим.

/**
 * group by day
 * @param query document {key1:123,key2:456}
 */
var count_by_day = function(query){
    return db.action.group(
    {
        keyf: function(doc) {
            var date = new Date(doc.time);
            var dateKey = (date.getMonth()+1)+"/"+date.getDate()+"/"+date.getFullYear();
            return {'date': dateKey};
        },
        cond:query,
        initial: {count:0},
        reduce: function(obj, prev) {
          prev.count++;
        }
    });
}

count_by_day({this:'is',the:'query'})
2
ответ дан phnessu4 26 August 2018 в 21:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: