1

У меня есть коллекция MongoDB, которая содержит набор документов. Каждый документ имеет ISODate date и целое число id (не _id). id: X указано, что существует для date: D, если в коллекции есть документ с указанием значений полей { id: X, date: D }. Так, например:Как вычислить разницу двух запросов?

{ id: 1, date: 1/1/2000 } 
{ id: 1, date: 1/2/2000 } 
{ id: 1, date: 1/3/2000 } 
{ id: 1, date: 1/4/2000 } 
{ id: 2, date: 1/2/2000 } 
{ id: 2, date: 1/3/2000 } 
{ id: 3, date: 1/3/2000 } 

Я хотел бы отслеживать id сек с течением времени, как они создаются и уничтожаются изо дня в день. Используя приведенные выше данные, в диапазоне дат 1/1/2000 до 1/4/2000:

1/1/2000: id 1 is created 
1/2/2000: id 2 is created 
1/3/2000: id 3 is created 
1/4/2000: id 2 is destroyed 
1/4/2000: id 3 is destroyed 

Я думаю, что лучший способ решить это будет день цикла на день, посмотрим, что существуют id s между сегодня и на следующий день, и выполняйте заданную разницу. Например, чтобы получить набор идентификаторов, созданных и уничтоженных на 1/2/2000, мне нужно выполнить два установочных различие между массивами в любой день:

var A = [ <ids that exist on 1/1/2000> ]; 
var B = [ <ids that exist on 1/2/2000> ]; 
var created_set = set_difference(B, A); // Those in B and not in A 
var destroyed_set = set_difference(A, B); // Those in A and not in B 

я могу использовать команду find() получить курсоры для A и B, но я не знаю, как выполнить set_difference между двумя курсорами.

Моим другим вариантом было использование конвейера агрегации, но я не могу думать о том, как сформулировать трубопровод таким образом, чтобы я мог использовать оператор $setDifference.

Будучи новичком MongoDB, я уверен, что я думаю о проблеме неправильно. Неужели это можно сделать? Что мне не хватает?

+1

Что именно ваша цель? найти все изменения, произошедшие между двумя датами? генерировать список всех измененных когда-либо? – jtmarmon

+0

@jtmarmon Моя цель - создать список создания и уничтожить даты для каждого идентификатора, найденного в коллекции. Второй список приведенных выше данных показывает, когда различные иды создаются и уничтожаются, это то, что я буду делать. – fbrereto

+0

Является ли дата форматом ISODate? – chridam

ответ

2
db.mystuff.aggregate([ 
    {$group: {_id: '$id', created: {$first: '$date'}, destroyed: {$last: '$date'}}} 
]) 
+2

Добрый Господь, это потрясающе. – fbrereto

+2

Это не работает, если есть пробелы – mnemosyn

+0

@mnemosyn Это может быть правдой, однако для моих целей 'id' будет существовать ровно в одном смежном блоке дат. – fbrereto

1

Предположим, у вас есть следующий сбор образцов:

db.collection.insert([ 
    { id: 1, date: ISODate("2000-01-01") }, 
    { id: 1, date: ISODate("2000-01-02") }, 
    { id: 1, date: ISODate("2000-01-03") }, 
    { id: 1, date: ISODate("2000-01-04") }, 
    { id: 2, date: ISODate("2000-01-02") }, 
    { id: 2, date: ISODate("2000-01-03") }, 
    { id: 3, date: ISODate("2000-01-03") } 
]); 

Следующая агрегация даст вам некоторое направление к тому, что вы пытаетесь достичь с помощью $setDifference оператора:

var start = new Date(2000, 0, 1); 
var end = new Date(2000, 0, 2) 
db.collection.aggregate([ 
    { 
     "$match":{ 
      "date": { 
       "$gte": start, 
       "$lte": end 
      } 
     } 
    }, 
    { 
     $group: { 
      _id: "$date",    
      "A": { 
       "$addToSet": { 
        "$cond": [ 
         { "$eq": [ "$date", start ] }, 
         "$id", 
         false 
        ] 
       } 
      }, 
      "B": { 
       "$addToSet": { 
        "$cond": [ 
         { "$eq": [ "$date", end ] }, 
         "$id", 
         false 
        ] 
       } 
      } 
     } 
    }, 
    { 
     "$project": { 
      "A": { 
       "$setDifference": [ "$A", [false] ] 
      }, 
      "B": { 
       "$setDifference": [ "$B", [false] ] 
      } 
     } 
    }, 
    { 
     "$project": { 
      "_id": 0, 
      "date": "$_id", 
      "created_set": { 
       "$setDifference": [ "$B", "$A" ] 
      }, 
      "destroyed_set": { 
       "$setDifference": [ "$A", "$B" ] 
      } 
     } 
    } 
]); 

Выход:

{ 
    "result" : [ 
     { 
      "date" : ISODate("2000-01-02T00:00:00.000Z"), 
      "created_set" : [2, 1], 
      "destroyed_set" : [] 
     }, 
     { 
      "date" : ISODate("2000-01-01T00:00:00.000Z"), 
      "created_set" : [], 
      "destroyed_set" : [1] 
     } 
    ], 
    "ok" : 1 
} 
+1

Это близко к тому, что я искал - краткий набор идентификаторов, которые идут и идут между двумя разными датами. – fbrereto