Using Sequelize with ES6 Promises? - node.js

I'm using Sequelize to connect to a Postgres database. I have this code:
return Promise.resolve()
.then(() => {
console.log('checkpoint #1');
const temp = connectors.IM.create(args);
return temp;
})
.then((x) => console.log(x))
.then((args) =>{
console.log(args);
args = Array.from(args);
console.log('checkpoint #2');
const temp = connectors.IM.findAll({ where: args }).then((res) => res.map((item) => item.dataValues))
return temp;
}
)
.then(comment => {
return comment;
})
.catch((err)=>{console.log(err);});
In the first .then block at checkpoint #1, the new record is successfully added to the Postgres database. In the console.log(x) in the next then block, this gets logged to the console:
{ dataValues:
{ id: 21,
fromID: '1',
toID: '2',
msgText: 'Test from GraphIQL',
updatedAt: Wed Oct 12 2016 09:52:05 GMT-0700 (PDT),
createdAt: Wed Oct 12 2016 09:52:05 GMT-0700 (PDT) },
_previousDataValues:
{ fromID: '1',
toID: '2',
msgText: 'Test from GraphIQL',
id: 21,
createdAt: Wed Oct 12 2016 09:52:05 GMT-0700 (PDT),
updatedAt: Wed Oct 12 2016 09:52:05 GMT-0700 (PDT) },
_changed:
{ fromID: false,
toID: false,
msgText: false,
id: false,
createdAt: false,
updatedAt: false },
'$modelOptions':
{ timestamps: true,
instanceMethods: {},
classMethods: {},
validate: {},
freezeTableName: false,
underscored: false,
underscoredAll: false,
paranoid: false,
rejectOnEmpty: false,
whereCollection: null,
schema: null,
schemaDelimiter: '',
defaultScope: {},
scopes: [],
hooks: {},
indexes: [],
name: { plural: 'IMs', singular: 'IM' },
omitNul: false,
sequelize:
{ options: [Object],
config: [Object],
dialect: [Object],
models: [Object],
modelManager: [Object],
connectionManager: [Object],
importCache: {},
test: [Object],
queryInterface: [Object] },
uniqueKeys: {},
hasPrimaryKeys: true },
'$options':
{ isNewRecord: true,
'$schema': null,
'$schemaDelimiter': '',
attributes: undefined,
include: undefined,
raw: undefined,
silent: undefined },
hasPrimaryKeys: true,
__eagerlyLoadedAssociations: [],
isNewRecord: false }
In the .then((args) => code block at checkpoint #2, args comes in as undefined.
How do I get args to contain an array of results from checkpoint #1?

.then((x) => console.log(x))
.then((args) =>{
is like doing
.then((x) => {
console.log(x);
return undefined;
})
.then((args) =>{
because console.log returns undefined. That means the undefined value will be what gets passed to the next .then.
The easiest approach would be to explicitly
.then((x) => {
console.log(x);
return x;
})
or in a shorter version using the comma operator
.then((x) => (console.log(x), x))

Related

server doesn't send response for Sequelize many to many relationship query

I am new to sequelize and node js. I have been trying to implement Sequelize Many-to-Many Association using node.js, express with PostgreSQL database following this tutorial. I have implemented a single table and retrieve data correctly without any issue. But in many-to-many relationships, I can only print data to console and in postman and chrome, it keeps loading around a minute and wait without loading data. Here are my code files.
db config file
const dbConfig = require("../config/db.config.js");
const Sequelize = require("sequelize");
const sequelize = new Sequelize(dbConfig.DB, dbConfig.USER, dbConfig.PASSWORD, {
host: dbConfig.HOST,
dialect: dbConfig.dialect,
operatorsAliases: false,
define: {
timestamps: true,
freezeTableName: true
},
pool: {
max: dbConfig.pool.max,
min: dbConfig.pool.min,
acquire: dbConfig.pool.acquire,
idle: dbConfig.pool.idle
}
});
const db = {};
db.Sequelize = Sequelize;
db.sequelize = sequelize;
db.actor = require("./actor.model.js")(sequelize, Sequelize);
db.film = require("./film.model.js")(sequelize, Sequelize);
db.film_actor = require("./film_actor.model.js")(sequelize, Sequelize);
db.film.belongsToMany(db.actor, {
through: db.film_actor,
as: "actors",
foreignKey: "film_id",
});
db.actor.belongsToMany(db.film, {
through: db.film_actor,
as: "films",
foreignKey: "actor_id",
});
module.exports = db;
filmController file
const db = require("../models");
const Film = db.film;
const Actor = db.actor;
//find all films including actors
exports.findAll = () => {
return Film.findAll({
include: [
{
model: Actor,
as: "actors",
attributes: ["first_name", "last_name"],
through: {
attributes: [],
}
},
],
})
.then((film) => {
console.log(film[5]);
return film;
})
.catch((err) => {
console.log(">> Error while retrieving films: ", err);
});
};
// find film by film id
exports.findById = (req, res) => {
const film_id = req.params.id;
return Film.findByPk(film_id, {
include: [
{
model: Actor,
as: "actors",
attributes: ["first_name", "last_name"],
through: {
attributes: [],
}
},
],
})
.then((films) => {
return films;
})
.catch((err) => {
console.log(">> Error while finding film: ", err);
});
};
film.route file
module.exports = app => {
const film = require("../controllers/film.controller.js");
var router = require("express").Router();
// Retrieve all films
router.get("/films", film.findAll);
// Retrieve a single actor with id
router.get("/films/:id", film.findById);
app.use('/api', router);
};
server.js file
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const filmController = require("./app/controllers/film.controller");
const app = express();
const db = require("./app/models");
db.sequelize.sync();
var corsOptions = {
origin: "http://localhost:8081"
};
app.use(cors(corsOptions));
// parse requests of content-type - application/json
app.use(express.json());
// parse requests of content-type - application/x-www-form-urlencoded
app.use(express.urlencoded({ extended: true }));
// simple route
app.get("/", (req, res) => {
res.json({ message: "Welcome to bezkoder application." });
});
db.sequelize.sync().then(() => {
// run();
});
require("./app/routes/actor.routes")(app);
require("./app/routes/film.routes")(app);
// app.get('/films',filmController.findAll);
// set port, listen for requests
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
As per my understanding, the issue should be about the routing. I created route for many to many associations as the same way I did for singe table(actor) but this problem occurred. I put a console log under findAll() method in filCcontroller and it prints the data in the console along with the query.
This is the output on my console
Executing (default): SELECT "film"."film_id", "film"."title", "film"."description", "film"."release_year", "film"."language_id", "film"."rental_duration", "film"."length", "actors"."actor_id" AS "actors.actor_id", "actors"."first_name" AS "actors.first_name", "actors"."last_name" AS "actors.last_name" FROM "film" AS "film" LEFT OUTER JOIN ( "film_actor" AS "actors->film_actor" INNER JOIN "actor" AS "actors" ON
"actors"."actor_id" = "actors->film_actor"."actor_id") ON "film"."film_id" = "actors->film_actor"."film_id";
film {
dataValues: {
film_id: 166,
title: 'Color Philadelphia',
description: 'A Thoughtful Panorama of a Car And a Crocodile who must Sink a Monkey in The Sahara Desert',
release_year: 2006,
language_id: 1,
rental_duration: 6,
length: 149,
actors: [
[actor], [actor],
[actor], [actor],
[actor], [actor],
[actor]
]
},
_previousDataValues: {
film_id: 166,
title: 'Color Philadelphia',
description: 'A Thoughtful Panorama of a Car And a Crocodile who must Sink a Monkey in The Sahara Desert',
release_year: 2006,
language_id: 1,
rental_duration: 6,
length: 149,
actors: [
[actor], [actor],
[actor], [actor],
[actor], [actor],
[actor]
]
},
_changed: Set {},
_options: {
isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
include: [ [Object] ],
includeNames: [ 'actors' ],
includeMap: { actors: [Object] },
includeValidated: true,
attributes: [
'film_id',
'title',
'description',
'release_year',
'language_id',
'rental_duration',
'length'
],
raw: true
},
isNewRecord: false,
actors: [
actor {
dataValues: [Object],
_previousDataValues: [Object],
_changed: Set {},
_options: [Object],
isNewRecord: false
},
actor {
dataValues: [Object],
_previousDataValues: [Object],
_changed: Set {},
_options: [Object],
isNewRecord: false
},
actor {
dataValues: [Object],
_previousDataValues: [Object],
_changed: Set {},
_options: [Object],
isNewRecord: false
},
actor {
dataValues: [Object],
_previousDataValues: [Object],
_changed: Set {},
_options: [Object],
isNewRecord: false
},
actor {
dataValues: [Object],
_previousDataValues: [Object],
_changed: Set {},
_options: [Object],
isNewRecord: false
},
actor {
dataValues: [Object],
_previousDataValues: [Object],
_changed: Set {},
_options: [Object],
isNewRecord: false
},
actor {
dataValues: [Object],
_previousDataValues: [Object],
_changed: Set {},
_options: [Object],
isNewRecord: false
}
]
}
any help would be greatly appreciated.

Sequelize and response request GraphQL

I try to have a response on my request GraphQL.
I tried many things but currently I have always the Sequence response, and no the Buckets response (belongs To relation).
I have 2 tables :
Sequence [id | is_active]
Bucket [id | fk_language_id | fk_sequence_id | is_active]
model/sequence.js
'use strict';
module.exports = (sequelize, DataTypes) => {
// define sequence
const Sequence = sequelize.define('sequence', {
is_active: {type: DataTypes.BOOLEAN}
});
Sequence.associate = function (models) {
models.Sequence.hasMany(models.Bucket, {
foreignKey: 'fk_sequence_id'
});
return Sequence;
};
model/bucket.js
'use strict';
module.exports = (sequelize, DataTypes) => {
const Bucket = sequelize.define('bucket', {
code : {type: DataTypes.STRING},
is_active: {type: DataTypes.BOOLEAN}
});
Bucket.associate = function (models) {
models.Bucket.belongsTo(models.Language, {
foreignKey: 'fk_language_id',
});
models.Bucket.belongsTo(models.Sequence, {
foreignKey: 'fk_sequence_id',
});
};
return Bucket;
};
schema.js
# Sequence
type Sequence {
id: Int!,
code: String,
buckets: [Bucket],
is_active: Boolean
}
# Bucket
type Bucket {
id: Int!,
code: String
blocks: [Block]
is_active: Boolean
}
# SequenceInput
input SequenceInput {
buckets: [BucketInput],
is_active: Boolean
}
# BucketInput
input BucketInput {
code: String,
fk_language_id: Int,
fk_sequence_id: Int,
is_active: Boolean
}
type Query {
sequences: [Sequence]
sequence(id: Int): Sequence
buckets: [Bucket]
bucket(id: Int): Bucket
}
type Mutation {
createSequence(input: SequenceInput): Sequence,
}
Request GraphQL
mutation {
createSequence(input: {
is_active: false,
buckets: [
{fk_language_id: 2, code: "Test"}
]
}) {
is_active,
buckets {
id,
code
}
}
}
But I have this result, the Buckets doesn't load :
{
"data": {
"createSequence": {
"is_active": false,
"buckets": []
}
}
}
my mutation :
...
Sequence : {
buckets(sequence) {
return models.Bucket.findAll({
where: {id: sequence.id}
});
},
...
},
...
Mutation : {
createSequence(_, {input}) {
let sequenceId = 0;
// Create Sequence
return models.Sequence.create(input)
.then((sequence) => {
sequenceId = sequence.id;
console.log('sequence created');
// Create Bucket
// Foreach on buckets
return Promise.map(input.buckets, function (bucket) {
bucket.fk_sequence_id = sequenceId;
console.log('bucket created');
return models.Bucket.create(bucket);
})
})
.then(() => {
console.log('load created', sequenceId);
return models.Sequence.findOne({
where : {id: sequenceId},
include: [
{
model: models.Bucket,
where: { fk_sequence_id: sequenceId }
}
]
}).then((response) => {
console.log(response);
return response;
})
});
},
}
The final console.log show many informations...
sequence {
dataValues:
{ id: 416,
is_active: false,
created_at: 2019-03-29T20:33:56.196Z,
updated_at: 2019-03-29T20:33:56.196Z,
buckets: [ [Object] ] },
_previousDataValues:
{ id: 416,
is_active: false,
created_at: 2019-03-29T20:33:56.196Z,
updated_at: 2019-03-29T20:33:56.196Z,
buckets: [ [Object] ] },
_changed: {},
_modelOptions:
{ timestamps: true,
validate: {},
freezeTableName: true,
underscored: false,
paranoid: false,
rejectOnEmpty: false,
whereCollection: { id: 416 },
schema: null,
schemaDelimiter: '',
defaultScope: {},
scopes: {},
indexes: [],
name: { plural: 'sequences', singular: 'sequence' },
omitNull: false,
createdAt: 'created_at',
updatedAt: 'updated_at',
sequelize:
Sequelize {
options: [Object],
config: [Object],
dialect: [Object],
queryInterface: [Object],
models: [Object],
modelManager: [Object],
connectionManager: [Object],
importCache: [Object],
test: [Object] },
hooks: {} },
_options:
{ isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
include: [ [Object] ],
includeNames: [ 'buckets' ],
includeMap: { buckets: [Object] },
includeValidated: true,
attributes: [ 'id', 'is_active', 'created_at', 'updated_at' ],
raw: true },
isNewRecord: false,
buckets:
[ bucket {
dataValues: [Object],
_previousDataValues: [Object],
_changed: {},
_modelOptions: [Object],
_options: [Object],
isNewRecord: false } ] }
Your mutation resolver returns a Promise, which resolves into a Model instance. The promise in question is returned on this line:
return models.Sequence.create(input)
.
As such, the server will wait until that promise is resolved before passing the value forward. Other actions were also waiting on that promise, but they were not the promises returned, so they will not be waited for.
All you have to do is wait for all of your operations to finish before resolving your promise.
createSequence: async (parent, { input }) => {
const sequence = await models.Sequence.create({
is_active: input.is_active
})
if (!input.buckets) return sequence
// You may have to modify your Sequence.buckets resolver to avoid fetching buckets again.
sequence.buckets = await Promise.all(input.buckets.map(bucket => {
// You can avoid these if checks by implementing stricter input types.
// e.g. buckets: [BucketInput!]!
if (!bucket) return null
return models.Bucket.create({
...bucket,
fk_sequence_id: sequence.id
})
}))
return sequence
}
Also, make sure your Sequence.buckets resolver isn't overwriting buckets with faulty data. The resolver you've provided will try to match bucket primary keys with a sequence primary key instead of matching the correct foreign keys with a primary key.
Here's a resolver that will work:
buckets: (parent) => (
parent.buckets // This line may conflict with some of your code and cause problems.
|| models.Bucket.findAll({
where: {fk_sequence_id: parent.id}
})
)

NodeJS + mongoose - user dynamic database globally

I am using NodeJS, ExpressJS, express-session, connect-mongo and mongoose. I want to create a database for every user. On login the database connection should be globally to use.
This is the: loginController
exports.loginPost = (req, res, next) => {
const email = req.body.email;
const pass = req.body.password;
const pin = req.body.pin;
if (email && pass && pin) {
User.findOne({ email })
.then(u => {
bcrypt.compare(pass, u.password, (err, result) => {
if (!err) {
bcrypt.compare(pin, u.pin, (err2, result2) => {
if (!err2) {
let msg = {};
global.userDB = null;
msg.success = [{ text: "You are now logged in..." }];
req.session.loggedIn = true;
req.session.userId = u._id;
req.session.role= u.role;
const Mongoose = require("mongoose").Mongoose;
const inst = new Mongoose();
let db = "user-" + orgid;
global.userDB = inst.connect(
"mongodb://localhost:27017?authSource=dbWithUserCredentials",
{
useNewUrlParser: true,
auth: { authSource: "admin" },
user: "root",
pass: "root",
dbName: db,
autoReconnect: true
}
);
return res.redirect("/");
} else {
console.log(err2);
}
});
} else {
return res.render("login", {
req,
msg: null
});
}
});
})
.catch(err => {
return res.render("login", {
req,
msg: err
});
});
}
};
This is the adressModel:
const aschema = global.userDB.Schema;
var AdressSchema = new aschema({
name: {
type: String
}
});
var Address = global.userDB.model("Adress", AdressSchema);
module.exports = Address;
When I'm running a page where I'm using this model, i see this on the console when I'm using this command: "console.log(global.userDB)";
NativeConnection {
base:
Mongoose {
connections: [ [Circular] ],
models: {},
modelSchemas: {},
options: { pluralization: true },
plugins: [ [Array], [Array], [Array] ] },
collections: {},
models: {},
config: { autoIndex: true },
replica: false,
hosts: null,
host: 'localhost',
port: 27017,
user: 'root',
pass: 'root',
name: 'user-undefined',
options:
{ pass: 'root',
user: 'root',
auth: { authSource: 'admin' },
useNewUrlParser: true,
db: { forceServerObjectId: false, w: 1 },
server: { socketOptions: {}, auto_reconnect: true },
replset: { socketOptions: {} },
mongos: undefined },
otherDbs: [],
states:
[Object: null prototype] {
'0': 'disconnected',
'1': 'connected',
'2': 'connecting',
'3': 'disconnecting',
'4': 'unauthorized',
'99': 'uninitialized',
disconnected: 0,
connected: 1,
connecting: 2,
disconnecting: 3,
unauthorized: 4,
uninitialized: 99 },
_readyState: 2,
_closeCalled: false,
_hasOpened: false,
_listening: false,
db:
Db {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
s:
{ databaseName: 'user-undefined',
dbCache: {},
children: [],
topology: [Server],
options: [Object],
logger: [Logger],
bson: BSON {},
authSource: undefined,
readPreference: undefined,
bufferMaxEntries: -1,
parentDb: null,
pkFactory: undefined,
nativeParser: undefined,
promiseLibrary: [Function: Promise],
noListener: false,
readConcern: undefined },
serverConfig: [Getter],
bufferMaxEntries: [Getter],
databaseName: [Getter] } }
Can someone say, why i get an 'undefined' in the database-name, but when I console.log the 'db'-variable there is the correct user._id.
Thanks!

Aggregate function returns null GraphQL

I am testing a basic aggregation function using counts from Sequelize and here's my type Counts:
type Creserve {
id: ID!
rDateStart: Date!
rDateEnd: Date!
grade: Int!
section: String!
currentStatus: String!
user: User!
cartlab: Cartlab!
}
type Counts {
section: String!
count: Int
}
type Query {
getBooking(id: ID!): Creserve!
allBookings: [Creserve]
getBookingByUser(userId: ID): Creserve
upcomingBookings: [Creserve]
countBookings: [Counts]
}
I am using countBookings as my query for aggregate functions and here's my resolver for the query:
countBookings: async (parent, args, {models}) =>
{
const res = await models.Creserve.findAndCountAll({
group: 'section',
attributes: ['section', [Sequelize.fn('COUNT', 'section'), 'count']]
});
return res.rows;
},
The query that it outputs is this:
Executing (default): SELECT "section", COUNT('section') AS "count" FROM "Creserve" AS "Creserve" GROUP BY "section";
And tried this query in my psql shell and it's working fine:
section | count
---------+-------
A | 2
R | 2
However, when I tried querying countBookings in my GraphQL Playground, section is returned but not the count:
{
"data": {
"countBookings": [
{
"section": "A",
"count": null
},
{
"section": "R",
"count": null
}
]
}
}
Is there something I missed out? Or is this a bug? This is the answer I tried following to with this example: https://stackoverflow.com/a/45586121/9760036
Thank you very much!
edit: returning a console.log(res.rows) outputs something like this:
[ Creserve {
dataValues: { section: 'A', count: '2' },
_previousDataValues: { section: 'A', count: '2' },
_changed: {},
_modelOptions:
{ timestamps: true,
validate: {},
freezeTableName: true,
underscored: false,
underscoredAll: false,
paranoid: false,
rejectOnEmpty: false,
whereCollection: null,
schema: null,
schemaDelimiter: '',
defaultScope: {},
scopes: [],
indexes: [],
name: [Object],
omitNull: false,
hooks: [Object],
sequelize: [Sequelize],
uniqueKeys: {} },
_options:
{ isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
raw: true,
attributes: [Array] },
__eagerlyLoadedAssociations: [],
isNewRecord: false },
Creserve {
dataValues: { section: 'R', count: '2' },
_previousDataValues: { section: 'R', count: '2' },
_changed: {},
_modelOptions:
{ timestamps: true,
validate: {},
freezeTableName: true,
underscored: false,
underscoredAll: false,
paranoid: false,
rejectOnEmpty: false,
whereCollection: null,
schema: null,
schemaDelimiter: '',
defaultScope: {},
scopes: [],
indexes: [],
name: [Object],
omitNull: false,
hooks: [Object],
sequelize: [Sequelize],
uniqueKeys: {} },
_options:
{ isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
raw: true,
attributes: [Array] },
__eagerlyLoadedAssociations: [],
isNewRecord: false } ]
Here's for res.count:
Executing (default): SELECT "section", COUNT('section') AS "count" FROM "Creserve" AS "Creserve" GROUP BY "section";
[ { count: '2' }, { count: '2' } ]
Problem
Actually you are doing everything right here... but what is happening here is the sequlize doesn't return plain object... It always returns the data in form of instance like that
[ Creserve {
dataValues: { section: 'A', count: '2' },
_previousDataValues: { section: 'A', count: '2' },
_changed: {},
_modelOptions:
{ timestamps: true,
Solution
I am not sure but there is no other way instead of looping and makes
response to json object...
const array = []
res.rows.map((data) => {
array.push(data.toJSON())
})
return array

Writing A Mongoose Plug In- plugin() a method?

I am interested in writing a mongoose plug in to make all fields required. I know there are other ways to do this, but I like the idea of writing my own plug in.
From docs http://mongoosejs.com/docs/plugins:
// game-schema.js
var lastMod = require('./lastMod');
var Game = new Schema({ ... });
Game.plugin(lastMod, { index: true });
but when I create a model from my schema and look at the properties, I don't see a plugin() method:
var mongoose = require('mongoose');
var CpuSchema = require("../schemas/cpu");
var Cpu = mongoose.model('Cpu', CpuSchema);
console.log(Cpu);
module.exports = Cpu;
one#demo ~/cloudimageshare-monitoring/project $ node /home/one/cloudimageshare-monitoring/project/app/data/models/cpu.js
{ [Function: model]
base:
{ connections: [ [Object] ],
plugins: [],
models: { Cpu: [Circular] },
modelSchemas: { Cpu: [Object] },
options: { pluralization: true } },
modelName: 'Cpu',
model: [Function: model],
db:
{ base:
{ connections: [Object],
plugins: [],
models: [Object],
modelSchemas: [Object],
options: [Object] },
collections: { cpus: [Object] },
models: {},
replica: false,
hosts: null,
host: null,
port: null,
user: null,
pass: null,
name: null,
options: null,
otherDbs: [],
_readyState: 0,
_closeCalled: false,
_hasOpened: false,
_listening: false },
discriminators: undefined,
schema:
{ paths:
{ timeStamp: [Object],
avaiable: [Object],
status: [Object],
metrics: [Object],
_id: [Object],
__v: [Object] },
subpaths: {},
virtuals: { id: [Object] },
nested: {},
inherits: {},
callQueue: [],
_indexes: [],
methods: {},
statics: {},
tree:
{ timeStamp: [Object],
avaiable: [Function: Boolean],
status: [Function: String],
metrics: [Object],
_id: [Object],
id: [Object],
__v: [Function: Number] },
_requiredpaths: undefined,
discriminatorMapping: undefined,
_indexedpaths: undefined,
options:
{ id: true,
noVirtualId: false,
_id: true,
noId: false,
read: null,
shardKey: null,
autoIndex: true,
minimize: true,
discriminatorKey: '__t',
versionKey: '__v',
capped: false,
bufferCommands: true,
strict: true,
pluralization: true },
_events: {} },
options: undefined,
collection:
{ collection: null,
opts: { bufferCommands: true, capped: false },
name: 'cpus',
conn:
{ base: [Object],
collections: [Object],
models: {},
replica: false,
hosts: null,
host: null,
port: null,
user: null,
pass: null,
name: null,
options: null,
otherDbs: [],
_readyState: 0,
_closeCalled: false,
_hasOpened: false,
_listening: false },
queue: [ [Object] ],
buffer: true } }
Here on the model, I don't see a plugin() method.
The plugin method is defined on the Schema class and you can see it on your CpuSchema object.
On your Cpu model you can get it by calling
console.log(Cpu.schema.plugin)
From the mongoose source code on GitHub:
/**
* Registers a plugin for this schema.
*
* #param {Function} plugin callback
* #param {Object} opts
* #see plugins
* #api public
*/
Schema.prototype.plugin = function (fn, opts) {
fn(this, opts);
return this;
};
When you pass your plugin function to it it simply executes the function and passes the schema reference into it.

Resources