Combining Mongodb with future documents

I am looking for some recommendations on how best to approach this type of query in MongoDB.

I have a shopping base, each of which has a property course, as well as the date on which the person bought.

I want the shopping list to happen after someone bought the original product.

So - some pesudo requests here:

// first find everyone who signed up for course A
{ course: 'a' }

then

/*
  out of those people, filter for those who in the future signed up
  for another course
*/

{
  course: { $in: ['b','c','d']},
  date: { $gt: $courseA.purchaseDate }
}

Is this possible through aggregation? Or would I make several database calls for each initial purchase to check if there is a future?

Here is an example of how the data for each purchase will look:

{ email: 'wes@example.com', course: 'a', purchaseDate: 10 },
{ email: 'wes@example.com', course: 'b', purchaseDate: 20 }, // match
{ email: 'wes@example.com', course: 'c', purchaseDate: 5 }, // not
{ email: 'nancy@example.com', course: 'a', purchaseDate: 5 },
{ email: 'nancy@example.com', course: 'c', purchaseDate: 6 }, // match
{ email: 'nancy@example.com', course: 'b', purchaseDate: 10 }, // match
{ email: 'nancy@example.com', course: 'd', purchaseDate: 1 }, // not
+4
source share
3 answers

Twitter

.aggregate([
  // Project the target purchasedate
  { $match: { course: { $in: ['JS3', 'RDX', 'WTF', 'RFB', 'ES6']}}},
  { $project: {
    email: 1, amount: 1, course: 1, purchaseDate: 1,
    target: {
      $cond: {
        if: { $eq: ['$course', 'JS3'] },
        then: "$purchaseDate",
        else: 0,
      }
    }
  }},
  // Group records by email, storing the target and the highest encountered purchase date
  { $group: {
    _id: '$email',
    courses: { $push: '$course'},
    amounts: { $push: '$amount'},
    count: { $sum: 1 },
    spent: { $sum: '$amount' },
    target: { $first: '$target'},
    max: { $max: '$purchaseDate'}
  }},
  // // Check if the highest encountered date is greater then the target
  { $project: {
    email: 1, course: 1, amounts: 1, spent: 1, count: 1, courses: 1, target:1, max: 1,
    selected: { $cond: [{ $gt: ['$max', '$target']}, true, false] }
  }},
  // Filter out the non-matches
  { $match: {
    target: { $gt: 0 },
    selected: true,
    spent: { $gt: 0 },
  }},
  { $sort: { spent: -1 }}
])
+2

mapReduce :

const options = {
  query: { course: 'courseA' }, // filter only the A course purchased
  map: function(){
    // iterate over course to get the couseA timeStamp

    // for every course you may have here, compare to couseATime
    this.course.forEach(function(course){
       // extract all the timeStamps
    })

    // if courseTime > couseATime then emit
    // emit({_id:this._id, email:this.email}, 1)
  },
  reduce: function(key, val){ // key will be {_id:'', email:''}
    return val // not important
  }
}

Model
  .mapReduce(options)
  .then(function(docs){
  })

_id , != courseA .

.aggregate() .project() .match, TTimeStamp .

EDIT:
, ... , ,

...
// Emit every course with the same key (_id + email)
map(){
  emit({_id: this._id, email:this.email}, {course: this.course, date: this.couse.date})
},

reduce(key, values){
  // key is {_id:'', email:''} and is unique
  // values is an array of {course:'', date:''}
  var aDate
  var dates = []

  // Find other dates
  values.forEach(function(val){
    // isolate course A date => aDate = ...
    // populate dates[] with date + course name
  })

  // dates should be => [{courseB: 10, couseC: 15 ...}]
  // The mean used to saved the couse + date is up to you

  // filter dates $gt aDate
  dates = dates.filter(....)

  return dates
}

. reduce() , , :

  • ,
  • , reduce()

( , , - )

, , finalize(), mongoose.

0

Here is another alternative.

$lookupby joining another collection on emailand $redactarray based documents purchaseDateand courses.

db.purchases.aggregate({
    $match: {
        course: 'a'
    }
}, {
    $lookup: {
        from: "purchases",
        localField: "email",
        foreignField: "email",
        as: "userCourses"
    }
}, {
    $redact: {
        $cond: [{
            $or: [{
                $and: [{
                    $gt: ["$purchaseDate", "$$ROOT.purchaseDate"]
                }, {
                    course: {
                        $or: ['b', 'c', 'd']
                    }
                }]
            }, {
                $eq: ["$course", "$$ROOT.course"]
            }]
        }, "$$DESCEND", "$$PRUNE"]
    }
});

Output example

{
        "email" : "wes@example.com",
        "course" : "a",
        "purchaseDate" : 10,
        "userCourses" : [
                {
                        "email" : "wes@example.com",
                        "course" : "a",
                        "purchaseDate" : 10
                },
                {
                        "email" : "wes@example.com",
                        "course" : "b",
                        "purchaseDate" : 20
                }
        ]
}
{
        "email" : "nancy@example.com",
        "course" : "a",
        "purchaseDate" : 5,
        "userCourses" : [
                {
                        "email" : "nancy@example.com",
                        "course" : "a",
                        "purchaseDate" : 5
                },
                {
                        "email" : "nancy@example.com",
                        "course" : "c",
                        "purchaseDate" : 6
                },
                {
                        "email" : "nancy@example.com",
                        "course" : "b",
                        "purchaseDate" : 10
                }
        ]
}
0
source

Source: https://habr.com/ru/post/1668522/


All Articles