I am beginner in sailsjs, i have multiple databases but table structure is same. So i would like to use single model and controller for all these databases.
I know we can set connection attribute in model like this
module.exports = {
connection: 'mysqlServer1',
attributes: {
userid: {
type: 'integer',
primaryKey: true
},
fbid: {
type: 'string'
},
source: {
type: 'string'
}
}
}
};
But how can we set connection dynamically runtime?
Thanks
I know this is old, but I stumbled on it looking for a solution to different problem, thought I'd answer.
The simplest way is to just set environment variables and use defaults.
For example, if you put MODELA_CONN="mysqlServer1" in your .bash_profile, or lift sails with an export like export MODELA_CONN="mysqlServer1" && sails lift, then you can just use that:
module.exports = {
connection: process.env.MODELA_CONN || "defaultMysql",
...
}
I am afraid this isn't possible yet. The closest thing you can get to a dynamic connection is using the following npm package https://github.com/sgress454/sails-hook-autoreload.
This will automatically reload sailjs with the changed connection config, without to lift sails again. But it won't cover your problem during runtime.
Related
I'm a TypeScript newb trying to write a Node.js (Node.ts?) backend, and trying to go about the basics of setting up my server. I'm using ts-node version 8.6.2 and typescript version 3.7.5, and defining validation for some domain objects in the following way (in the ajv style):
// domain_obj_1.ts:
const commonSchema = {
type: 'object',
properties: {
foo: { type: 'string' },
},
};
export class DomainObject1 {
...
// domain_obj_2.ts:
const commonSchema = {
type: 'object',
properties: {
bar: { type: 'string' },
},
};
export class DomainObject2 {
...
However, ts-node-dev is spitting out the following error:
error TS2403: Subsequent variable declarations must have the same type.
Variable 'commonSchema' must be of type '{ type: string; properties: { foo: { type: string; }; }; }',
but here has type '{ type: string; properties: { bar: { type: string; }; }; }'.
I can only assume Typescript is detecting a collision of these separate declarations of commonSchema, but they're not being exported so I'm not sure how that's happening.
There's a lot I don't yet understand about TS and its use in Node, but this is surprising behavior and I'm wondering if there's something obvious I'm missing.
Figured out a way to get ts-node-dev to stop yelling at me, and it indicates there were at least a couple things wrong with my set-up. Hopefully this answer might provide enough breadcrumbs for someone else struggling with standing their own builds up:
I had require('ts-node/register') at the top of each of my knex migration files so I can write the code in modern ES syntax. Turns out this was probably causing a double-compilation problem which seems like has some unpredictable downstream effects.
It also turns out ts-node, which backs ts-node-dev, needs to explicitly be told where tsconfig.json file lives, either by setting the TS_NODE_PROJECT environment variable or passing the --project (-P) flag.
Addressing #1 seems to be sufficient to resolve the errors I was seeing, but for the sake of correctness I'm also addressing the missing config file so eventual compilation in prod is predictable.
I am starting to learn Sails.js and I want to know if there is a simpler way to set the default value in a model from a session variable? I am using Waterlock to do authentication and setting the user_id in a session variable like req.session.user_id. I have a message model, I want to default the 'from' field to this session variable. Is there a way to do this in Sails.js?
If you are using Sail's default ORM, Waterline, then model attributes have a defaultsTo option. The supplied value may be a function. You can look at the waterline documentation.
Sample Model
module.exports = {
attributes: {
description: {
type: 'string',
defaultsTo: 'No description.'
},
email: {
type: 'email',
required: true,
unique: true
},
alias: {
type: 'string',
defaultsTo: function(){
return this.email;
}
},
}
};
If the supplied value is a function, then the call to this function is bound to the values in the create.
For Model.create(values)..., if alias is null/undefined, then alias = defaultsTo.call(values) is used to get the value for alias.
So to use req.session.user_id you may have to include it during create.
Model.create({session: req.session,...}). I am not really sure, since I do not use Waterlock. And I'm not don't think this is the best way to go about it.
From my experience these extra values are ignored when using adapters such as sails-mysql, but if you are using sails-disk for development, then you might see that these extra values are persisted. You may want to delete them before you persist.
beforeCreate: function(values, cb){
delete values['session'];
cb();
}
I'm trying to deep populate a collection.
For example
// UnitType.js
name: { type: 'string' }
// Unit.js
unitType: {
model: 'unitType',
via: '_id',
required: true,
index: true
}
// Product.js
unit: {
model: 'unit',
via: '_id',
required: true,
index: true
},
The problem is, that - as far I know from internet research deep populate like
Product.find().populate('unit.unitType');
is currently not supported in sails. To achieve the result I want I currently
query Products with populate unit
query UnitTypes with the id from `product.unit.unitType``
.map() product.unit.unitType with the response
This is of course far from ideal. I also tried using toJSON in the model to "pre-populate" the unitType -> doesn't work since this doesn't support Promises.
There are quite a few threads on so and PR's on github on this issue, but so far I haven't found a solution to this problem. Is there any way to make this better?
You could try to replace Waterline ORM with Offshore ORM. There is a hook for sails to do that - sails-hook-orm-offshore.
It's quite easy to implement to your existing project, because its fork of Waterline wits some more features. Only cons i found is that sails-hook-validation
stopped working.
How to install
npm install sails-hook-orm-offshore --save
Configuration
.sailsrc
{
"hooks": {
"orm": false,
"pubsub": false
}
}
Defaults
config/globals.js
adapters: true,
models: true
Usage
Now you will be allowed to deep populate in your queries. For example (from documentation):
User.find()
.populate('foo.bar', { name: 'foo' }) //populate foo into user and bar into foo
.exec(function(err, users) {
console.log(users[0].foo.bar.name) // 'foo'
});
Second option
Merge deep populate with waterline
npm i Atlantis-Software/waterline#deepPopulate
So I have model Alarms which is associated with Site model and others... Is it possible somehow set that by default when are required Alarm.findAll().then() I didn’t need to specify which associated models I need? It is necessary because Alarms table are using in many different situations and some different apps but in my case I need only entries which has site.
Or may be somehow I can add default joins to the model?
Usually when I encounter situations like this, I would just make a module which returns a promise of the query (with joins). So, for example you could make an alarm_util module
exports.getAlarm = function() {
return Alarms.findAll({
include: [{
model: Site,
include: [{
model: OtherModel
}]
}]
});
};
module.exports = exports;
And use it anywhere in your code like
alarm_util.getAlarm().then(alarm => {
// The rest of your logic here...
});
We're rapidly developing an application that's using Mongoose, and our schema's are changing often. I can't seem to figure out the proper way to update a schema for existing documents, without blowing them away and completely re-recreating them from scratch.
I came across http://mongoosejs.com/docs/api.html#schema_Schema-add, which looks to be right. There's little to no documentation on how to actually implement this, making it very hard for someone who is new to MongoDB.
I simply want to add a new field called enabled. My schema definition is:
var sweepstakesSchema = new Schema({
client_id: {
type: Schema.Types.ObjectId,
ref: 'Client',
index: true
},
name: {
type: String,
default: 'Sweepstakes',
},
design: {
images: {
type: [],
default: []
},
elements: {
type: [],
default: []
}
},
enabled: {
type: Boolean,
default: false
},
schedule: {
start: {
type: Date,
default: Date.now
},
end: {
type: Date,
default: Date.now
}
},
submissions: {
type: Number,
default: 0
}
});
Considering your Mongoose model name as sweepstakesModel,
this code would add enabled field with boolean value false to all the pre-existing documents in your collection:
db.sweepstakesModel.find( { enabled : { $exists : false } } ).forEach(
function (doc) {
doc.enabled = false;
db.sweepstakesModel.save(doc);
}
)
There's nothing built into Mongoose regarding migrating existing documents to comply with a schema change. You need to do that in your own code, as needed. In a case like the new enabled field, it's probably cleanest to write your code so that it treats a missing enabled field as if it was set to false so you don't have to touch the existing docs.
As far as the schema change itself, you just update your Schema definition as you've shown, but changes like new fields with default values will only affect new documents going forward.
I was also searching for something like migrations, but didn't find it. As an alternative you could use defaults. If a key has a default and the key doesn't exist, it will use the default.
Mongoose Defaults
Default values are applied when the document skeleton is constructed. This means that if you create a new document (new MyModel) or if you find an existing document (MyModel.findById), both will have defaults provided that a certain key is missing.
I had the exact same issue, and found that using findOneAndUpdate() rather than calling save allowed us to update the schema file, without having to delete all the old documents first.
I can post a code snippet if requested.
You might use mongo shell to update the existing documents in a specific collection
db.SweeptakesModel.update({}, {$set: {"enabled": false}}, {upsert:false, multi:true})
I had a similar requirement of having to add to an existing schema when building an app with Node, and only found this (long ago posted) query to help.
The schema I added to by introducing the line in the original description of the schema and then running something similar to the following line, just the once, to update existing records:
myModelObject.updateMany( { enabled : { $exists : false } }, { enabled : false } )
'updateMany' being the function I wanted to mention here.
just addition to what Vickar was suggesting, here Mongoose Example written on Javascript (Nodejs):
const mongoose = require('mongoose');
const SweeptakesModel = mongoose.model(Constants.SWEEPTAKES,sweepstakesSchema);
SweeptakesModel.find( { enabled : { $exists : false } }).then(
function(doc){
doc.enabled = false;
doc.save();
}
)