2015-10-19 4 views
2

Мне нужно получить список недельных диапазонов для всех записей в моем MongoDB. Когда я нажимаю на недельный диапазон, он будет отображать только записи для этого диапазона. Нажатие на диапазон недель отправляет идентификатор недели (скажем, 42, то есть 42-я неделя вне 2015 года), он должен получить эти результаты.Получить все объекты за номер недели

Вопрос: Как я могу запросить набор записей с указанием номера недели и года? Это должно работать, не так ли?

SCHEMA:

var orderSchema = mongoose.Schema({ 
     date: Date, //ISO date 
     request: { 
      headers : { 
      ... 

Первый: Получить все идентификаторы неделю для всех объектов:

var query = Order.aggregate(
     [ 
      { 
       $project: 
       { 
        week: 
        { 
         $week: '$date' 
        } 
       } 
      }, 
      { 
       $group: 
       { 
        _id: null, 
        distinctDate: 
        { 
         $addToSet: 
         { 
          week: '$week' 
         } 
        } 
       } 
      } 
     ] 
    ); 

Результат:

distinctDate: Array[35] 
    0: Object 
     week: 40 
    1: Object 
     week: 37 
     ... 

Преобразовать в диапазонах недели, используя MomentJS и дисплей:

data.forEach(function(v, k) { 
     $scope.weekRanges.push(getWeekRange(v.week)); 
    }); 

    function getWeekRange(weekNum) { 

     var monday = moment().day("Monday").isoWeek(weekNum).format('MM-DD-YYYY'); 
     var sunday = moment().day("Sunday").isoWeek(weekNum).format('MM-DD-YYYY'); 
     ... 

Выход:

Week 
10-12-2015 to 10-18-2015 //week ID 42 
10-05-2015 to 10-11-2015 //week ID 41 
09-28-2015 to 10-04-2015 ... 
... 

Второе: Нажмите на неделю диапазоне и получить объекты в неделю ID:

var year = 2015; 
var weekID = weekParamID; //42 

    if (!Order) { 
     Order = mongoose.model('Order', orderSchema()); 
    } 

    var query = Order.aggregate(
     { 
      $project: 
      { 
       cust_ID : '$request.headers.custID', 
       cost : '$response.body.pricing.cost', 
       year : 
       { 
        $year: '$date' 
       }, 
       month : 
       { 
        $month: '$date' 
       }, 
       week: 
       { 
        $week: '$date' 
       }, 
       day: 
       { 
        $dayOfMonth: '$date' 
       } 
      } 
     }, 
     { 
      $match: 
      { 
       year : year, //2015 
       week : weekID //42 
      } 
     } 
    ); 

И если я нажимаю на неделю Range 10-12-2015 to 10-18-2015 (неделя ID 42), я получаю результаты с датами вне диапазона (10-19-2015):

10-19-2015  Order info 
10-18-2015  Order info 
10-19-2015  Order info 

Использование MongoDB командной строки:

db.mycollection.aggregate({ $project: { week: { $week: '$date' }, day: { $dayOfMonth: '$date' } } }, { $match: { week: 42 } } 

Результаты:

{ "_id" : "1bd482f6759b", "week" : 42, "day" : 19 } //shouldn't exceed week range 
{ "_id" : "b3d38759", "week" : 42, "day" : 19 } 

EDIT: Обновление

Таким образом, существует несоответствие с неделями ISO MongoDB (начинается в воскресенье) и Moment JS ISO (начинается в понедельник).

This SO post предлагает вычитание даты из запроса, поэтому дата Монго начинается в понедельник:

{ 
$project: 
    { 
    week: { $week: [ "$datetime" ] }, 
    dayOfWeek:{$dayOfWeek:["$datetime"]}} 
    }, 
{ 
$project: 
{ 
    week:{$cond:[{$eq:["$dayOfWeek",1]},{$subtract:["$week",1]},'$week']} 
} 
} 

Я реализовал это с моим запросом, но теперь он не возвращает два поля, которые мне нужно:

  cust_ID : '$request.headers.custID', 
      cost : '$response.body.pricing.cost' 

Запрос:

db.mycollection.aggregate(
     { 
      $project: 
      { 
       cust_ID : '$request.headers.custID', 
       cost : '$response.body.pricing.cost', 
       week: 
       { 
        $week: ['$date'] 
       }, 
       dayOfWeek: 
       { 
        $dayOfWeek: ['$date'] 
       } 
      } 
     }, 
     { 
      $project: 
      { 
       week: { 
        $cond: [ 
         { 
          $eq: [ 
           "$dayOfWeek", 1 
          ] 
         }, 
         { 
          $subtract: [ 
           "$week", 1 
          ] 
         }, '$week' 
        ] 
       } 
      } 
     }, 
     { 
      $match: 
      { 
       week : 42 
      } 
     } 
    ); 

Результатов:

{ "_id" : "387e2", "week" : 42 } 
{ "_id" : "ef269f6341", "week" : 42 } 
{ "_id" : "17482f6759b", "week" : 42 } 
{ "_id" : "7123d38759", "week" : 42 } 
{ "_id" : "ff89b1fb", "week" : 42 } 

Это не возвращает fieldsets я, указанный в $ проекте

+1

Вам нужно включить их снова во второй проект. Например. стоимость: «$ cost» – sheilak

+1

@sheilak, спасибо. Таким образом, mongodb $ cond fix не работает. Я возвращаю $ dayOfMonth, чтобы показать, в какой день месяца был размещен заказ obj, но его пока еще показываются дни (т.е. 10/19/2015 или даже 10/20/2015), которые находятся за пределами диапазона 10/12/2015 - 10/18/2015 – Growler

+0

Обновлен мой ответ. Ответ, который вы связали с конвертированием на неделю с начала недели, но не на стандартную неделю ISO. Стандартная неделя ISO отличается от MongoDB тем, как она определяет неделю 1 в начале года. Извините, у меня нет решения, но, надеюсь, несколько указателей, чтобы приблизиться. – sheilak

ответ

1

Оператор MongoDB $week считает неделю, чтобы начать в воскресенье, see docs:

неделя начинается в воскресенье, и неделе 1 начинается с первого воскресенья года ... Такое поведение аналогично оператору «% U» для стандартной библиотечной функции strftime .

Moment.JS's isoWeekday() использует неделю ISO, в котором недели недели начинаются в понедельник. Это также отличается тем, что он считает неделю 1 первой неделей с четвергом в ней.

Это несоответствие может объяснить поведение, которое вы видите.

E.g. если я сохранить этот документ в MongoDB, который является понедельником:

db.test.save({ "date" : new ISODate("2015-10-19T10:10:10Z") }) 

затем запустить агрегацию выше запрос, я получаю неделю 42.

Но если я запускаю следующее:

console.log(moment().day("Monday").isoWeek(42)) 

Я получаю приведенную ниже дату, которая не та, которую я первоначально сохранил в MongoDB, хотя это понедельник недели MongoDB.

Mon Oct 12 2015 

Как исправить это Я думаю, зависит от того, какое определение недели вам нужно.

Если вы довольны определением MongoDB $week, то, вероятно, легко найти/написать альтернативную реализацию, чтобы преобразовать номер недели в соответствующую дату. Вот одна библиотека, которая добавляет поддержку STRFTIME к Moment.js:

https://github.com/benjaminoakes/moment-strftime

Если вы хотите использовать формат ISO, это сложнее. В соответствии с вашими изменениями вы должны будете учитывать разницу начала недели. Но вам также нужно будет указать номер недели в начале года. Это различие означает, что номер недели strftime может иметь неделю 0, а ISO всегда начинается на 1-й неделе. В течение 2015 года похоже, что вам нужно добавить 1 неделю на неделю strftime, чтобы получить неделю ISO, а также учет за неделю но это не будет надежным в целом.

+0

Я пробовал реализовать изменения на стороне Монго. См. Выше edit – Growler

0

Начиная с MongoDB версии 3.4 вы можете использовать оператор агрегации $isoWeek.

Возвращает номер недели в формате ISO 8601, начиная от 1 до 53. Номера недель начинаются с 1 недели (с понедельника по воскресенье), который содержит первый четверг в году.

Дополнительную информацию об этом можно найти на странице MongoDB docs.

Смежные вопросы