Overriding Relation Remote Method In Strongloop Loopback - node.js

I have a User model and a Follower model which has HasManyThrough relation with User for the follower and followee.
How can I change the default __get__followers method parameters?

I figured out that I can juse add a new remote method the normal way.
loopback.remoteMethod(
UserModel.prototype.getFollows,
{
description: 'Get the users who are followed by the user',
accepts: [
{arg: 'page', type: 'Number', http: {source: 'query'}, required: true}
],
returns: {arg: 'data', type: 'object'},
http: {verb: 'get', path: '/follows'},
isStatic: false,
}
);

Yet another way. Tree hasMany Leaves and we want to override the __get__leaves relation handler of a Tree.
/**
* Before Remote handler
*
* #param {Object} ctx - Context
* #param {Function} next - Callback function
*/
Tree.beforeRemote('**', function (ctx, unused, next) {
if (ctx.method.name === '__get__leaves') {
return Tree.getLeaves(ctx)
}
next()
})
/**
* Override Relation handler
*
* #param {Object} ctx - Context
*/
Tree.getLeaves = (ctx) => {
ctx.res.sendStatus(200)
}

Related

Why the values of the parameter are not consoled at my function?

What im trying to do is to receive two parameters in req.params.
swagger
/**
* #swagger
* /clients/removeClients/{user_id}/{client_id}:
* put:
* summary: removing clients
* tags: [Clients]
* parameters:
* - name: user id
* description: User id
* type: string
* in: path
* required: true
* - name: client id
* description: client id
* type: string
* in: path
* required: true
* responses:
* 200:
* description: done
* 500:
* description: Some server error
*/
router.put("/removeTrustee/:user_id/:client_id", removeClient);
controller
exports.removeTrustee = asyncHandler(async (req, res, next) =>{
console.log(req.params)
res.status(200).json({
success: true,
data: {}
})
})
When I console.log the params in my terminal is showed like this:
{ user_id: '{user_id}', client_id: '{client_id}' }
and when I access one of them: console.log(req.params.user_id)
it will console just user_id
How can I receive the values that I put in the parameters?

How can I make an request params to mongo db from node js and swagger?

What I have tried is to get all the data by createdBy param. createdBy has a user phone number value.
controller
exports.getLocation = asyncHandler(async (req, res, next) => {
const createdBy = req.params.createdBy
console.log('created', createdBy) // its empty
const getLocation = await Location.find( {createdBy: createdBy} )
res.status(200).json({
success: true,
msg: "Getting all the locations of the user",
data: getLocation
})
})
routes
/**
* #swagger
* /location/getLocation/:createdBy:
* get:
* summary: getting the location of the user by phone number
* tags: [Location]
* requestBody:
* required: false
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Location'
*
* responses:
* 200:
* description: the location has been recivied
* 500:
* description: Some server error
*/
router.get("/getLocation/:createdBy", getLocation)
The idea is to put the param in a request body, to get all the data of the createdBy key in the database. The get method doesn't accept a request body.
How can I put a param so I can get the data from the database?
To let you know, I'm using the swagger request body to execute the API, and this API is for a react-native application.
You have to correct your swagger annotation for createdBy property,
use {createdBy} instead of :createdBy in URL
use parameters property of swagger and in that declare the createdBy property with path type
requestBody is not required because you are using GET request type
/**
* #swagger
* /location/getLocation/{createdBy}:
* get:
* summary: getting the location of the user by phone number
* tags: [Location]
* parameters:
* - name: createdBy
* description: Created By
* in: path
* required: true
* responses:
* 200:
* description: the location has been recivied
* 500:
* description: Some server error
*/
router.get("/getLocation/:createdBy", getLocation);

How to bulk "upsert" in bookshelf?

I need to import the data from a CSV file (around 20K rows) to my database. Some of the rows may already exist in the database, thus they only need to be updated, but the new rows must be inserted. If any of the operations fail, the transaction must be cancelled.
How can I do this? This is the code I was using:
var vehicle = {
id: row.id,
lastUpdate: moment(row.lastUpdate, 'DD/MM/YYYY - HH:mm').toDate(),
version: row.version,
color: row.color,
location: row.location,
status: row.status
};
Vehicle.forge({
id: row.id
})
.save(vehicle, { transacting: t, patch: true })
.then(model => {
console.log('*************' + vehicle.id);
})
.catch(Vehicle.NoRowsUpdatedError, err => {
// There are no rows for this chassis, so let's insert it
Vehicle.forge(vehicle)
.save(null, { transacting: t, method: 'insert' })
.then(model => {
console.log('++++++++++++++' + vehicle.id);
})
.catch(err => {
console.log(`INSERT ERROR: ${err.message}`);
t.rollback();
return res.json({ status: false, count: 0, error: err.message });
});
})
.catch(err => {
console.log(`UPDATE ERROR: ${err.message}`);
t.rollback();
return res.json({ status: false, count: 0, error: err.message });
});
This code is in a for loop, but it fails in the second iteration, probably because of concurrency between the promises.
I also tried to add a custom function to my model file, but it says that the function does not exist.
let bookshelf = require('./base');
var Vehicle,
Vehicles;
Vehicle = bookshelf.Model.extend({
tableName: 'vehicles',
/**
* Insert a model based on data
* #param {Object} data
* #param {Object} [options] Options for model.save
* #return {Promise(bookshelf.Model)}
*/
create: function (data, options) {
return this.forge(data).save(null, options);
},
/**
* Select a model based on a query
* #param {Object} [query]
* #param {Object} [options] Options for model.fetch
* #param {Boolean} [options.require=false]
* #return {Promise(bookshelf.Model)}
*/
findOne: function (query, options) {
options = extend({ require: true }, options);
return this.forge(query).fetch(options);
},
/**
* Select a model based on data and update if found, insert if not found
* #param {Object} selectData Data for select
* #param {Object} updateData Data for update
* #param {Object} [options] Options for model.save
*/
upsert: function (selectData, updateData, options) {
return this.findOne(selectData, extend(options, { require: false }))
.bind(this)
.then(function (model) {
return model
? model.save(
updateData,
extend({ patch: true, method: 'update' }, options)
)
: this.create(
extend(selectData, updateData),
extend(options, { method: 'insert' })
)
});
}
});
Vehicles = bookshelf.Collection.extend({
model: Vehicle
});
module.exports = {
Vehicle: bookshelf.model('Vehicle', Vehicle),
Vehicles: bookshelf.collection('Vehicles', Vehicles)
};
Instead of using bookshelf, you could utilize knex directly to do this. Just grab the instance of knex you pass to bookshelf, and you can use it like this:
knex.transaction((trx) => {
return Bluebird.map(vehicles, vehicle => {
const insert = knex('vehicles').insert(vehicle).toString();
delete vehicle.id;
const update = knex('vehicles').update(vehicle).toString();
const set = update.substring(18);
return trx.raw(`${insert} ON CONFLICT (id) DO UPDATE ${set}`);
});
});
We can utilize Knex's handy toString method to generate most of our raw query for us; in this way, we can do an upsert even though it's not directly supported by Knex. Bluebird's map function is perfect for cleanly handling an array of data like this and would let you await having to loop through it altogether.

Sails.js / Waterline - Create is not a function on model

I am new to both Node.js and the Sails.js framework. I am trying to build a website/application with the framework, but am having trouble getting the model part to work as expected. I have looked at the documentation quite a bit, but still am not able to perform this basic task. I am using the PostgreSQL adapter.
The stack is as follows:
TypeError: Fragrance.create is not a function\n at Object.module.exports.index (/home/kelly/workspace/Hawthorne-Acres/api/controllers/HomeController.js:16:19)\n at wrapper (/usr/local/lib/node_modules/sails/node_modules/#sailshq/lodash/lib/index.js:3250:19)\n at routeTargetFnWrapper (/usr/local/lib/node_modules/sails/lib/router/bind.js:181:5)\n at callbacks (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:164:37)\n at param (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:138:11)\n at param (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:135:11)\n at pass (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:145:5)\n at nextRoute (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:100:7)\n at callbacks (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:167:11)\n at alwaysAllow (/usr/local/lib/node_modules/sails/lib/hooks/policies/index.js:224:11)\n at routeTargetFnWrapper (/usr/local/lib/node_modules/sails/lib/router/bind.js:181:5)\n at callbacks (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:164:37)\n at param (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:138:11)\n at param (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:135:11)\n at pass (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:145:5)\n at nextRoute (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:100:7)\n at callbacks (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:167:11)\n at module.exports (/usr/local/lib/node_modules/sails/lib/hooks/cors/clear-headers.js:14:3)\n at routeTargetFnWrapper (/usr/local/lib/node_modules/sails/lib/router/bind.js:181:5)\n at callbacks (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:164:37)\n at param (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:138:11)\n at pass (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:145:5)"
Fragrance.js (located in the api/models folder):
module.exports = {
attributes: {
fragranceName: {
type: 'string',
required: true
},
listings: {
collection: "listing",
via: "fragrance"
}
}
};
The controller that calls the function
/**
* HomeController
*
* #description :: Server-side logic for managing Homes
* #help :: See http://sailsjs.org/#!/documentation/concepts/Controllers
*/
var Fragrance = require("../models/Fragrance");
module.exports = {
/**
* `HomeController.Index()`
*/
index: function(req, res) {
Fragrance.create({ fragranceName: 'Vanilla' }).exec(function(err, rec) {
console.log(rec.id);
});
return res.render("index", { title: "Welcome" });
},
/**
* `HomeController.About()`
*/
about: function(req, res) {
console.log("About place");
return res.render("about", { title: "About" });
},
/**
* `HomeController.Contact()`
*/
contact: function(req, res) {
return res.render("contact", { title: "Contact" });
}
};
It is probably something obvious, but I have made an effort to figure it out on my own, just without success. As such, any help would be appreciated.
Thanks.
The models in model folder are globally available. You can disable the functionality in config/globals.js. So you can drop
var Fragrance = require("../models/Fragrance");
Then you can create a record via:
Fragrance.create method
or
sails.models.fragrance.create method (Notice the model name is in lowercase.)
Personally, I prefer the second pattern and turning off the availability of models globally.

callQueue method in mongoose schema constructor

I have problem to understand the line: this.callQueue = [ [ 'pre', [ 'save', beforeSave ] ] ];
Here is the line where it locates at:
var util = require('util');
var Schema = require('mongoose').Schema;
var counter = require('./counter');
var utils = require('./utils');
/**
* Base Schema constructor.
*
* ####Example:
*
* var user = new BaseSchema({ name: String });
* var post = new BaseSchema({ content: String });
*
* // setting schema options
* new BaseSchema({ name: String }, { _id: false, autoIndex: false })
*
* ####Options:
*
* - [autoIndex](/docs/guide.html#autoIndex): bool - defaults to true
* - [bufferCommands](/docs/guide.html#bufferCommands): bool - defaults to true
* - [capped](/docs/guide.html#capped): bool - defaults to false
* - [collection](/docs/guide.html#collection): string - no default
* - [id](/docs/guide.html#id): bool - defaults to true
* - [_id](/docs/guide.html#_id): bool - defaults to true
* - `minimize`: bool - controls [document#toObject](#document_Document-toObject) behavior when called manually - defaults to true
* - [read](/docs/guide.html#read): string
* - [safe](/docs/guide.html#safe): bool - defaults to true.
* - [shardKey](/docs/guide.html#shardKey): bool - defaults to `null`
* - [strict](/docs/guide.html#strict): bool - defaults to true
* - [toJSON](/docs/guide.html#toJSON) - object - no default
* - [toObject](/docs/guide.html#toObject) - object - no default
* - [versionKey](/docs/guide.html#versionKey): bool - defaults to "__v"
*
*
* #param {Object} definition
* #inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
* #event `init`: Emitted after the schema is compiled into a `Model`.
* #api public
*/
function BaseSchema() {
Schema.apply(this, arguments);
this.callQueue = [ [ 'pre', [ 'save', beforeSave ] ] ];
this.add({
_id: Number,
createTime: Number,
modifyTime: Number
});
}
/**
* set default value before save to db
*
*
* #param {Function} next
*/
function beforeSave(next) {
var model = this;
if(model.isNew) {
model.modifyTime = model.createTime = Date.now();
counter.getNextId(model.collection.name + '_id', function(err, id) {
model._id = id;
next();
});
}
else {
model.modifyTime = Date.now();
next();
}
}
util.inherits(BaseSchema, Schema);
module.exports = BaseSchema;
Also I think the usage is like this
var Post = new BaseSchema({
title: String,
tags: Array,
content: String,
creator: String,
avatar: String,
comments: [Comment],
pv: Array,
reprint: { type: Object, default: {} },
lastUpdateTime: String
}, options);
Post.pre('save', function(next) {
if(this.isNew) {
this.lastUpdateTime = utils.formatDate(Date.now());
}
next();
})
Also here is the project github link: [https://github.com/smadey/node-mongoose-blog]. The code is in models file
this.callQueue = [ [ 'pre', [ 'save', beforeSave ] ] ] is internally adding a pre save middleware for all the schemas that are inherited from it. For example is the Post schema will have now two pre save hooks attached to it:
First one is the beforeSave hook attached with BaseSchema
Second one is the hook that is attached with Post schema
Internally all hooks are stored in callQueue array. If you log that variable, you'll see two callbacks for those two hooks:
> console.log(Post.callQueue)
[ [ 'pre', [ 'save', [Function: beforeSave] ] ],
[ 'pre', { '0': 'save', '1': [Function] } ] ]

Resources