MongoDB dateDiff between multiple documents

♀尐吖头ヾ 提交于 2019-12-06 06:16:48

You need to use the $min and $max operators which respectively return the minimum and maximum value for "BookingTime" in your $group stage. The last stage in the pipeline is the $redact stage where you use a simple "date" math using the $divide and $subtract arithmetic operators.to return those documents where the number of days between first "service" and last "service" is greater than 30

db.collection.aggregate( [ 
    { "$group": { 
        "_id": "$Email",  
        "date1": { "$min": "$BookingTime" }, 
        "date2": { "$max": "$BookingTime" } 
    }}, 
    { "$redact": { 
        "$cond": [ 
             { "$gte": [ 
                 { "$divide": [ 
                     { "$subtract": [ "$date2", "$date1" ] }, 
                     1000 * 60 * 60 * 24 
                 ]}, 
                 30 
             ]}, 
             "$$KEEP", 
             "$$PRUNE" 
        ] 
    }}
])

Which returns:

{
        "_id" : "xyz@xyz.com",
        "date1" : ISODate("2015-12-27T06:00:00Z"),
        "date2" : ISODate("2016-01-27T06:00:00Z")
}

Another way to do this is by using the $cond operator in a $project stage to avoid a collection scan.

db.collection.aggregate( [ 
    { "$group": { 
        "_id": "$Email", 
        "date1": { "$min": "$BookingTime" },
        "date2": { "$max": "$BookingTime" }, 
        "count": { "$sum": 1 } 
    }},
    { "$match": { "count": { "$gte": 2 } } }, 
    { "$project": { 
        "emails": { 
            "$cond": [ 
                { "$gte": [ 
                    { "$divide": [ 
                        { "$subtract": [ "$date2", "$date1" ] }, 
                        1000 * 60 * 60 * 24 
                    ]}, 
                    30 
                ] }, 
                "$_id", 
                false 
            ] 
        } 
    }}, 
    { "$match": { "emails": { "$ne": false } } } 
])

You can get first sales date and last sales date by $min and $max:

db.services.aggregate({
    $group: {
       "_id" :"$Email",
       lastSalesDate: { $max: "$BookingTime" },
       firstSalesDate: { $min: "$BookingTime" }
    }   
  }
)

After that you can add filter based on lastSalesDate. You can calculate ISO date which 30 days before. ex. ISODate("2015-12-28T00:00:00.000Z"). By $lt , you will get customers of 30 days before.

db.services.aggregate(
  {
    $group: {
       "_id" :"$Email",
       lastSalesDate: { $max: "$BookingTime" },
       firstSalesDate: { $min: "$BookingTime" }
    }   
  },
  { 
    $match : {
       "lastSalesDate" : { $lt: ISODate("2015-12-28T00:00:00.000Z") }
    }
  }
)

Results like:

{ 
    "_id" : "abc@abc.com", 
    "lastSalesDate" : ISODate("2015-12-26T06:00:00.000+0000"), 
    "firstSalesDate" : ISODate("2015-12-26T06:00:00.000+0000")
}

This is what I used finally

db.services.aggregate( 
    {$group: {
       "_id" :"$Email",
       count:{$sum:1},
       lastSalesDate: { $max: "$BookingTime" },
       firstSalesDate: { $min: "$BookingTime" }
    },
    {$project:{
            _id:1,count:1,dateDifference: { $divide:[ {$subtract: [ "$lastSalesDate", "$firstSalesDate" ]},86400000] }
        }
    },
    {$match:{
          count:{$gt:1},dateDifference:{$gt:20}
        }
    }
  }
)

Count > 1 helped to filter the records which never repeated and datedifferentce > 20 is for days as I already converted milliseconds to days using division operation.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!