sequelize: Build not persistent instance with relations - node.js

Assuming I have Model and RelatedModel types in my application, Model.hasMany(RelatedModel) and RelatedModel.belongsTo(Model, {foreignKey:{allowNull: false, name: 'model_id'}});, is it possible to build Model instance with RelatedModel set?
When I'm using
var model = Model.build({});
model.createRelatedModel({});
model.save();
application fails, as model does not have id when built and id assigned only after save() called, so relatedModel ending up with model_id set to NULL.
Is it possible to work with non-persistent model and it's relations and then save all with model.save()? (using transaction will be also nice)

Related

Create dynamic collection in MongoDB using Sails.js

I am working with SailsJs+MongoDB API. I have to create New colletion in mongoDB .Name of colletion will be in request Parameter.
example:
Suppose I want to create 'Users' collection in 'mongoDbDatabase' database
by following request.
{
"collectionName" : "Users",
"dbName" :"mongoDbDatabase"
}
Now is there any way to create dynamic collection in mongoDB using req.param('collectionName) variable ?
To use all the tools that Sails provides, you have to add code (before you start your app) for each Model / Collection you are planning to interact with. As a result, creating a collection dynamically will mean you can't take advantage of the whole data - framework sails provides.
Are you sure you need a dynamic collection? Why not a defined collection differentiated by attributes?
If you really need to do this from Sails, it looks like you can get access to the underlying raw mongo database:
var db = AnyModel.getDatastore().manager; // the database will be as defined in config/models.js or config/connections.js
var collectionName = 'Widgets';
db.createCollection(collectionName);
// note, even if this works, something like 'Widgets.find' will not.

Unable to get reference to HasOne Property Inside Remote Method

I have ExtentedUser Model which has two hasOne relationships to two models
driver and customer (both having a belongTo realtionship back to the ExtentedUser) and they are also the Extended from User base model).
after the use of
ExtentedUser.afterRemote('create', function(context, user, next){
//in here i am unable to get
// reference to driver or customer model
//eg user.driver or user.customer
}
My bad what i was doing wrong is that i using model name as property.
user.driver /where driver is modelName
but i should have used the relationship name
which was
user.drivers /where drivers is RelationShipName

Associations in Sequelize migrations

My app currently uses the Sequelize sync() method to create the database, and I want to change it to use the migrations system.
One of my model has belongsTo() associations with other models, and I don't really know how to make the initial migration code for these associations.
Do I have to manually create the foreign key with SQL queries, or is there some methods available?
Case 1: Database initialization
If your purpose is to add relations during initialization of database structure it is better to just use sync method instead of manually adding them using migrations. If your models are properly designed and have relations defined, they will be created automatically during execution of sync method.
Take a look at sequelize express example. In models directory you have three files:
index.js - which includes all models
task.js - task model
user.js - user model
Look at task.js content, starting from line 7 the following code creates a relation between User and Task models:
classMethods: {
associate: function(models) {
Task.belongsTo(models.User, {
onDelete: "CASCADE",
foreignKey: {
allowNull: false
}
});
}
}
If you correctly prepare your relations in model files, sync will create the foreign keys for you. Migrations aren't necessary in this case.
I encourage you to read the whole express-example readme.md and browse repository files to see how the things work with express and sequelize.
Case 2: Database structure migration
In case you already have some data which you want to keep, you need to use migration script, because the only way for sync to restructure your database is to destroy it completely alongside with all its data.
You can read about basic migrations in the sequelize docs. Unfortunately docs do not cover creating a relation. Let's assume you want to create the following relation: User belongs to Group. To create column on the user side of relation, you may use addColumn method.
queryInterface.addColumn(
'user',
'group_id',
{
type: Sequelize.INTEGER,
allowNull: true
}
)
Unfortunately there isn't a nice function (yet) to create the foreign key constraint for you, but you can do it manually using sequelize query method. Postgresql example:
queryInterface.sequelize.query("ALTER TABLE user
ADD CONSTRAINT user_group_id_fkey FOREIGN KEY (group_id)
REFERENCES group (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE;");
Edit: Added database structure migration case
Adding this as an answer instead of a comment (not enough rep) for #aryeh-armon answer above. It's the table name that you need to make sure exists rather than the model name. i.e. if your model is named Job and your db table is named Jobs then the migration would look look like this instead.
jobId: {
type: Sequelize.INTEGER,
references: {
model: "Jobs",
key: "id"
}
},
you can add references to the migrations
Exmaple:
user_id: {
type: Sequelize.BIGINT,
references: {
model: "users",
key: "id"
}
},
Just make sure the model you are referencing exists.
After lots of searching, I found a couple of blog posts explaining what I wanted to do. The first one no longer exists, and here's the second one
Apparently it's not really the common way to do it, but it seems more logical to me. If you want to use only the migrations, you have to use SQL queries to create the initial migration.
But anyway, I think that ezpn is right about creating the initial database with sync, and then migrate. It seems easier than using umzug and only use migrations.

Getting id of just saved object In Sequelize?

So I have this code:
//defining partner
var Partner = sequelize.define('Partner', {
order: Sequelize.INTEGER,
image: Sequelize.STRING,
}, {
tableName: 'partners',
});
//creating partner instance
var partner=Partner.build();
partner.save().success(function(newpartner){
console.log(newpartner.id);
});
When this code gets executed, 2 instances of partner are inserted to the database. The second one is pushed when I access id property of partner.
Here is the log from the console:
Executing (default): INSERT INTO `partners` (`updatedAt`,`createdAt`) VALUES ('2014-08-16 13:13:26','2014-08-16 13:13:26');
Executing (default): INSERT INTO `partners` (`id`,`createdAt`,`updatedAt`) VALUES (DEFAULT,'2014-08-16 13:13:26','2014-08-16 13:13:26');
I need to get id of the partner and send it to client after persisting it to the database. How do I do it properly?
For now I just access id property without invoking save(), since it saves object anyway. However this is not documented. Is there a proper way to do it?
I managed to isolate the problem.
My mistake came from reading docs not thoroughly enough. Apparently setting associated object pushes entity to the Database (unlike in Doctrine, for example).
So my entity was saved during execution of the following code (not included in the question):
Partner.setManager(manager);
Where Manager is an entity in oneToMany relationship to Partner.
So the solution was to remove the save() call and use the success callback from the setManager()

Loading related entities when dealing with Models and Collections from Backbone to Express / Mongoose

I have a UserService object that is essentially a Service with additional configuration parameters and is attached to a User. In my View I would like to render a list of these UserServices however the model is formed as such:
UserService = Backbone.Model.extend({
defaults: {
id: 0,
user_id: 0, // This needs to reference the user object somehow
service_id: 0, // This needs to reference the service object somehow
length: 216000,
price: 1000
}
});
If I bind this model to the view, what is rendered ends up being the service_id instead of the parameter I need to render: service.name.
My questions are:
What should be stored in the UserService model at service? The full service object? Mongoose ID? Some other ID? (Please specify a suggestion)
Where should I get the information for this service.name / When should I pull the Service object to get that information? It would be nice to be able to do service.name in the view when rendering...
Is there a function to chain--upon loading the model, load related models that are needed?
Overall I just need an understanding of how related models work in Backbone / Express / Mongoose.
Any help is appreciated!
Update: After doing a bit of reading I have a couple different methods I can see:
Within the constructor / initializer load the Service object into the UserService object based on the reference ID returned from the server.
My questions with that one then become... what is the reference ID? Where do I put the newly retrieved object into, possibly in place of the ID?
Use the toJSON method to return an asthetic version of the UserService where it retreives the Service object and would return an object with the service name in it's place:
{
id: ???,
service_name: "this was retrieved from the service object in the toJSON method",
length: "1 hour", // converted from within the toJSON method
price: 10.00 // converted from cents to dollars in the toJSON method
}
Or maybe a combination? Thoughts?
Parse models handle loading related entities well, there is also library called Backbone Relational that can help with this.
Otherwise, my best recommendation is to store the object's ID and fetch the related entity upon success of fetching the first entity.
Anyone needing a code example just comment here and I'll see what I can come up with.

Resources