'mongoose.Query.prototype.exec() patching not working with populate

This is the code I have written for implementing redis caching in queries:

mongoose.Query.prototype.exec = async function () {
  if (!this.__useCache || !client.__connected) {
    return exec.apply(this);
  }
  const key = JSON.stringify(
    Object.assign({}, this.getQuery(), {
      collection: this.mongooseCollection.name,
    })
  );
  // see if key exists
  const cachedValue = await client.HGET(this.__hashKey, key);

  // if yes, return it
  if (cachedValue) {
    const doc = JSON.parse(cachedValue);
    const result = Array.isArray(doc)
      ? doc.map((d) => new this.model(d))
      : new this.model(doc);
    console.log('result', result);

    return result;
  }
  // if no, store it in redis and return
  const result = await exec.apply(this);
  if (typeof result === 'object') {
    await client.HSET(this.__hashKey, key, JSON.stringify(result));

    // cache will expire after 24 hrs by default
    client.expire(this.__hashKey, this.__duration || 86400);
  }
  return result;
};

This works perfectly fine for all queries that doesn't 'populate'. But with populate it gets stuck at await exec.apply(this). Why does it happen and how do I fix it ?



Solution 1:[1]

I solved it by saving the reference to original exec() inside the Query object instead of just a local variable and calling that instead of the local variable. Like this :

mongoose.Query.prototype._exec = mongoose.Query.prototype.exec;

mongoose.Query.prototype.exec = async function () {
//redis functionality
.
.
.
return await mongoose.Query.prototype._exec.apply(this, arguments);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 anandsr-dev