To make MongoDB database manipulation easy, we can use the Mongoose NPM package to make working with MongoDB databases easier.
In this article, we’ll look at how to use Mongoose to manipulate our MongoDB database.
Discriminators and Single Nested Documents
We can define discriminators on single nested documents.
For instance, we can write:
async function run() {
const { createConnection, Types, Schema } = require('mongoose');
const db = createConnection('mongodb://localhost:27017/test');
const shapeSchema = Schema({ name: String }, { discriminatorKey: 'kind' });
const schema = Schema({ shape: shapeSchema });
schema.path('shape').discriminator('Circle', Schema({ radius: String }));
schema.path('shape').discriminator('Square', Schema({ side: Number }));
const Model = db.model('Model', schema);
const doc = new Model({ shape: { kind: 'Circle', radius: 5 } });
console.log(doc)
}
run();
We call discriminator
on the shape
property with:
schema.path('shape').discriminator('Circle', Schema({ radius: String }));
schema.path('shape').discriminator('Square', Schema({ side: Number }));
We call the discriminator
method to add the Circle
and Square
discriminators.
Then we use them by setting the kind
property when we create the entry.
Plugins
We can add plugins to schemas.
Plugins are useful for adding reusable logic into multiple schemas.
For example, we can write:
const loadedAtPlugin = (schema, options) => {
schema.virtual('loadedAt').
get(function () { return this._loadedAt; }).
set(function (v) { this._loadedAt = v; });
schema.post(['find', 'findOne'], function (docs) {
if (!Array.isArray(docs)) {
docs = [docs];
}
const now = new Date();
for (const doc of docs) {
doc.loadedAt = now;
}
});
};
async function run() {
const { createConnection, Types, Schema } = require('mongoose');
const db = createConnection('mongodb://localhost:27017/test');
const gameSchema = new Schema({ name: String });
gameSchema.plugin(loadedAtPlugin);
const Game = db.model('Game', gameSchema);
const playerSchema = new Schema({ name: String });
playerSchema.plugin(loadedAtPlugin);
const Player = db.model('Player', playerSchema);
const player = new Player({ name: 'foo' });
const game = new Game({ name: 'bar' });
await player.save()
await game.save()
const p = await Player.findOne({});
const g = await Game.findOne({});
console.log(p.loadedAt);
console.log(g.loadedAt);
}
run();
We created th loadedAtPlugin
to add the virtual loadedAt
property to the retrieved objects after we call find
or findOne
.
We call schema.post
in the plugin to listen to the find
and findOne
events.
Then we loop through all the documents and set the loadedAt
property and set that to the current date and time.
In the run
function, we add the plugin by calling the plugin
method on each schema.
This has to be called before we define the model
.
Otherwise, the plugin won’t be added.
Now we should see the timestamp when we access the loadedAt
property after calling findOne
.
Conclusion
We can add the discriminators to singly nested documents.
Also, we can add plugins to add reusable logic into our models.