I'm using sequelize v5.21 and sequelize-cli v5.5.1 for a MySQL database.
I'm currently trying to create some association 1:M under the following model generated code from the cli like so:
Where: a is the source and b the target.
model.associate = function (models) {
// associations can be defined here
a.hasOne(models.b);
}
and the other model, i have:
model.associate = function (models) {
// associations can be defined here
b.belongsTo(models.a);
}
Finally, im using this code to check the associations by creating a entries:
a.create({
...
}).then(a => {
return a.createB({
...,
}).catch(err => console.log(err));
}).catch(err => console.log(err)
);
In which i'm getting an error on the "a.createB()..." as is not a function...
So, i was curious enough and tried doing the associations right before checking the associations like so:
a.hasOne(b);
b.belongsTo(a);
In which works just fine...
My question is, is the "model.associate" property still working on the v5^?
Note: I have used the check associations method provided in the sequelize documentation but i prefer this one since it's easier to read.
I found nothing about model.associate in Sequelize documentation for v5, but in my project I'm using this code in main models directory:
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
where db is autogenerated by sequelize-cli models imported by sequelize['import']
Related
I'm trying desperately to setup Firebase database sharding into an Ionic v3 (Angular 4) app in order to decrease the Realtime Database load values.
I almost made it work, except one small detail.
So what I've done is the following:
initialized a new app
const app2 = firebase.initializeApp({ databaseURL: "https://app2.firebaseio.com/" }, "app2");
then in a service I'm using AngularFireDatabase:
constructor(private afDatabase: AngularFireDatabase) {}
then when I want to simply get a list of items from the second database I do
this.afDatabase.list(firebase.database(app2).ref('/items'));
which works just fine.
But the problem now is that when I pass in a query object, like this
this.afDatabase.list(firebase.database(app2).ref('/items'), {
query: {
orderByChild: "item_id",
equalTo: 5
}
});
this query is completely ignored, it actually returns the whole list under /items.
The problem is caused by a bug is in list() and object() methods implementation in database.ts file under angularfire2 package, version 2.0.0-beta.8
More exactly, this line
isRef: () => FirebaseObjectFactory(urlOrRef)
should actually be
isRef: () => FirebaseObjectFactory(urlOrRef, opts)
both under list() and object() functions.
With this fix, and a rebuild of angularfire2 package, I managed to made it work.
I'm using strapi alongside knex, however strapi doesn't create any migrations and when you edit a content type (Model) by deleting a property or renaming it, it doesn't delete the targeted property, it just creates a new one, and when you delete a model it doesn't actually delete the table on the database.
This is really annoying because you'll end up with a lot of redundancies and unused tables and fields while developing.
What I'm doing is overriding the Strapi controllers that are responsible for creating, removing or updating a model and I want to be able to create a migration with the new schema on those controllers and then run it so I keep my database clean and up-to-date with strapi's models.
I know about the existence of knex.migrate.make however it doesn't seem to address my issue and the docs don't really tell you how to provide the migration fields to that function.
I was able to also find this http://knexjs.org/#custom-migration-sources however once again the docs are not very clear on what options I can provide and how to solve my issue.
Ideally I would want to end up with something like:
updateModel({attributes, table}){
const updatedSchena = attributes
knex.migrate.make(`update_${table.name}_table`, updatedSchema);
}
Edit:
I was able to create the new migration at run time but the contents of the file remain empty.
This is what I have so far
New custom-migration-sources as indicated in the docs:
class MyMigrationSource {
// Must return a Promise containing a list of migrations.
// Migrations can be whatever you want, they will be passed as
// arguments to getMigrationName and getMigration
constructor(name, attributes) {
this.name = name
this.attributes = attributes
console.log('attributes: ', attributes)
}
getMigrations() {
// In this example we are just returning migration names
return Promise.resolve(['migration1'])
}
getMigrationName(migration) {
return migration;
}
getMigration() {
return {
up(knex) {
//const migrate = require('widget-knex-schema')
return migrate.createTable(knex, this.name, this.attributes)
},
down(knex) {
return knex.schema.dropTableIfExists(this.name)
}
}
}
}
Instantiate the new migration source
const migration = new MyMigrationSource(modelJSON.collectionName, formatedAttributes)
Create the new migration with the custom configuration:
knex.migrate.make(`update_${name}_table`, {
migrationSource: migration
})
And the result is a new migration with these contents:
exports.up = function(knex) {
};
exports.down = function(knex) {
};
NOTE: I know that ´widget-knex-schema´is working because I use for other manually created migrations.
Can anyone link to any working examples or solutions on how to create migrations in run time?
I recently started using Bookshelf. Examples in the documentation aren't very clear to me. This is one such example:
var knex = require('knex')({
client: 'mysql',
connection: process.env.MYSQL_DATABASE_CONNECTION
});
var bookshelf = require('bookshelf')(knex);
var User = bookshelf.Model.extend({
tableName: 'users',
posts: function() {
return this.hasMany(Posts);
}
});
var Posts = bookshelf.Model.extend({
tableName: 'messages',
tags: function() {
return this.belongsToMany(Tag);
}
});
var Tag = bookshelf.Model.extend({
tableName: 'tags'
})
User.where('id', 1).fetch({
withRelated: ['posts.tags']
}).then(function(user) {
console.log(user.related('posts').toJSON());
}).catch(function(err) {
console.error(err);
});
After the creation of three models (User, Posts, and Tag) - there is a query.
What exactly is the meaning of this query?
User.where('id', 1).fetch({withRelated: ['posts.tags']}).then(function(user) {
console.log(user.related('posts').toJSON());
}).catch(function(err) {
console.error(err);
});
What are withRelated, 'posts.tags', user.related('posts')? Can anyone tell me in simplest form, what those terms are and where they come from?
Finally, what is the meaning of the complete query?
It's all answered in the documentation, although not everything in the exact same place, so I can understand your confusion. You really have to read the whole thing to better understand it.
From the documentation of Model.fetch():
withRelated: Relations to be retrieved with Model instance. Either one or more relation names (...) A single property, or an array of properties can be specified as a value for the withRelated property.
From Collection.fetch():
The withRelated option may be specified to fetch the models of the collection, eager loading any specified relations named on the model.
From Collection.load():
... Nested eager loads can be specified by separating the nested relations with .
From Model.related():
The related method returns a specified relation loaded on the relations hash on the model, or calls the associated relation method and adds it to the relations hash if one exists and has not yet been loaded.
All of these are involved in the eager loading of relations on models.
What these methods do is load some data from a table that is related to the parent model's table in some way. In the example you posted, the User model has some Posts and the Posts themselves have some tags, so the relations go something like:
User
|_ Post
|_ Tag
These are expressed as methods on each model, for example, posts: function() { ... } in the User model.
When you specify a relation to eager load using withRelated, you use these method names. Furthermore you can eager load deeply nested relations by separating them with a ., and that's what you're seeing in the example.
So, putting everything together what that example is doing is searching for the User with id = 1 and also retrieving all the posts that belong to that user as well as all the tags that belong to all the posts that belong to the user.
Then to access these related objects you use the related('something') method of the model.
I wanted to test the models of my Trails.js project with mocha. I use the trailpack-waterline to load my models into the Waterline ORM.
Following the Trails Docs I created a User.test.js:
'use strict'
const assert = require('assert')
describe('User Model', () => {
let User
before(() => {
assert(global.app.models.User)
User = global.app.models.User
})
it('should exist', () => {
assert(User)
})
})
This runs without any error.
But I cannot instantiate the model in any way. Following the example of the Docs new User({...}) should create a new user object, but this code throws an error saying User is not a constructor. And neither the example of the Waterline Docs using User.create({...}) seems to work.
Printing out the User model shows it consists of only two methods: [ 'getModelName', 'getTableName' ].
How do I instantiate a waterline Model for unit testing?
It's because global.app.models.User is your model's definition and not the waterline model. This one is under global.app.orm.User, after that you can use User.create without any problem
I don't mean remove a document or documents. I mean remove the model entirely so that mongoose is no longer aware of it. After declaring a model I can't figure out how to make mongoose forget that model so that it could be recreated.
mongoose.model('Book', bookSchema);
mongoose.model('Book', bookSchema);
Currently the above throws an exception.
OverwriteModelError: Cannot overwrite 'Book' model once compiled.
I'd like to be able do something like this...
mongoose.model('Book', bookSchema);
mongoose.removeModel('Book');
mongoose.model('Book', bookSchema);
...and not get any errors. Any ideas?
try this
delete mongoose.connection.models['Book'];
and then re-register/re-initialize it . it will work fine
It appears that you'd have to overwrite some of the source code in order to be able to remove a model an add a new one since Mongoose makes sure that a model doesn't exist before it's willing to create a new one, which may or may not be more than you care to do:
if (this.models[name] && !collection) {
// model exists but we are not subclassing with custom collection
if (schema instanceof Schema && schema != this.models[name].schema) {
throw new MongooseError.OverwriteModelError(name);
}
return this.models[name];
}
Line 587 https://github.com/LearnBoost/mongoose/blob/master/lib/connection.js
Question Author's Update:
Thanks to this answer I discovered that you can access the models defined on the connection through connection.models. In my scenario I was testing a mongoose plugin with Mocha and and I wanted to clear the models between each unit test.
afterEach(function () {
mongoose.connection.models = {};
});
You can use the deleteModel method
mongoose.deleteModel(modelName);
This is actually a better way to get rid of models, schemas and collections in mongoose
mongoose.connections.forEach(connection => {
const modelNames = Object.keys(connection.models)
modelNames.forEach(modelName => {
delete connection.models[modelName]
})
const collectionNames = Object.keys(connection.collections)
collectionNames.forEach(collectionName => {
delete connection.collections[collectionName]
})
})
const modelSchemaNames = Object.keys(mongoose.modelSchemas)
modelSchemaNames.forEach(modelSchemaName => {
delete mongoose.modelSchemas[modelSchemaName]
})
Reference: https://github.com/Automattic/mongoose/issues/2874#issuecomment-388588452