Created
October 8, 2022 22:31
-
-
Save zisan34/64f502944920550db2347fde9d21ed44 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This file is responsible for caching mongo model instance for specific time. | |
* Usage example: | |
* Store.findOne(query, fields).cacheResults(1 * 60).exec(); // it'll cache result for specified seconds | |
* Store.findOne(query, fields).removeCache().exec(); // it'll remove any existing cache | |
*/ | |
// @ts-nocheck | |
import mongoose from 'mongoose'; | |
import redisClient from './redisClient'; | |
mongoose.Query.prototype.cacheResults = function (time: number) { | |
this.cache_results = true; | |
this.cacheTimeSeconds = time; | |
return this; | |
}; | |
mongoose.Query.prototype.removeCached = function () { | |
this.remove_cached = true; | |
return this; | |
}; | |
mongoose.Query.prototype.getCacheKey = function () { | |
const key = JSON.stringify({ | |
collectionName: this.mongooseCollection.name, | |
op: this.op, | |
options: this.getOptions(), | |
filter: this.getFilter(), | |
projection: this.projection(), | |
populatedPaths: this.getPopulatedPaths(), | |
}); | |
return key; | |
}; | |
const exec = mongoose.Query.prototype.exec; | |
mongoose.Query.prototype.exec = async function () { | |
if (this.remove_cached) { | |
// remove_cached is true so remove cache for the key | |
const key = this.getCacheKey(); | |
redisClient.del(key); | |
} | |
if (this.cache_results) { | |
// cache_results is true so cache result for the key | |
const key = this.getCacheKey(); | |
const cachedResults = await redisClient.get(key); | |
if (cachedResults) { | |
// if you found cached results return it; | |
const result = JSON.parse(cachedResults); | |
const options = this.getOptions(); | |
const projection = this.projection(); | |
// create model instance again from the results so that you get all the model functionalities with cached data | |
return Array.isArray(result) | |
? // eslint-disable-next-line new-cap | |
result.map((document) => new this.model(document, projection, options)) | |
: // eslint-disable-next-line new-cap | |
new this.model(result, projection, options); | |
} else { | |
// get results from Database then cache it | |
const result = await exec.apply(this, arguments); | |
redisClient.set(key, JSON.stringify(result), 'EX', this.cacheTimeSeconds); | |
return result; | |
} | |
} else { | |
return exec.apply(this, arguments); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I am trying to implement exactly the same logic in my app but
const result = await exec.apply(this, arguments);
this part of the code is giving me null in case of
findOne
andfind
calls even when matching documents are present in the DBany idea how to overcome this problem?