Search code examples
javascriptnode.jsmongoosevirtual

Use mongoose virtuals to count entries conditionally


I want add a virtual to my mongoose schema. The goal of the virual is to count the number of document in the same collection that are less than the referenced document. So for example, I've the following collection:

  const mySchema = new mongoose.Schema({
    timestamp: {
      type: Number
    }
  })

  mySchema.virtual('count', {
    ref: 'mySchema',
    count: true,
    localField: 'timestamp',
    foreignField: 'timestamp',
    match: function (ref, cmp) {
      return ref.timestamp < cmp.timestamp // does not work
    }
  })

  const M = mongoose.model('mySchema', mySchema)

So when I do the following:

  await M.create({
    timestamp: 10
  })

  await M.create({
    timestamp: 20
  })

  await M.create({
    timestamp: 30
  })

  console.log((await M.find({ timestamp: 30 })).count)

I see "undefined" in the console, but "count" should be "2" because of the match-function, but this function is never called because of the foreign-/local-field-match (I also don't know if I can access the "ref" and "cmp" parameters in the match-function. When I remove the foreign-/local-field parameter, it throws me an error because these fields seems to be mandatory. I want simply add a condition like "count all entries where the timestamp is lower than the current entry". Any idea how I can do this?


Solution

  • mySchema.virtual('count').get( async function() {
        return await collection.count(.....);
    })
    

    In addition to using the above, you need mongoose-lean-virtuals in order to show count when it's using .lean();

    Explain: Your method also requires mongoose to call an additional query.