Sails 0.10 & Many-to-Many association - Get all associated data, not the first only - node.js

I have 2 models with a Many-to-Many association. My code to associate these two models is working well (it create a new collection item_languages__language_items with the corresponding documents inside). But then I have trouble to get all the associated data (languages) of a specific item. I'm using MongoDB.
// Item.js
module.exports = {
schema: true,
autoPK: false,
attributes: {
uuid: {
type: 'string',
primaryKey: true,
unique: true,
required: true,
uuidv4: true
},
languages: {
collection: 'language',
via: 'items',
dominant: true
}
}
}
// Language.js
module.exports = {
schema: true,
autoPK: false,
attributes: {
code: {
type: 'string',
primaryKey: true,
required: true,
minLength: 2,
maxLength: 2,
unique: true
},
items: {
collection: 'item',
via: 'languages'
}
}
}
Data stored in the item_languages__language_items collection:
/* 0 */
{
"language_items" : "es",
"item_languages" : "69e4f3a3-1247-4a06-ae2d-9df27ac9495b",
"_id" : ObjectId("5330bcebf8e0b61509c771d5")
}
/* 1 */
{
"language_items" : "fr",
"item_languages" : "69e4f3a3-1247-4a06-ae2d-9df27ac9495b",
"_id" : ObjectId("5330bd26f8e0b61509c771d6")
}
/* 2 */
{
"language_items" : "en",
"item_languages" : "69e4f3a3-1247-4a06-ae2d-9df27ac9495b",
"_id" : ObjectId("5330bedcc076355b09da3ccd")
}
Now in my ItemController.js, I want to get a specific item with all associated languages:
Item
.findOne({uuid: '69e4f3a3-1247-4a06-ae2d-9df27ac9495b'})
.populate('languages')
.exec(function (e, r) {
console.log(r.toJSON());
});
But here I get my item with only 1 associated language, when I expected to get the 3 associated languages.

This appears to be a bug in the current beta implementation of sails-mongo which keeps populate from working properly with custom-defined keys. Please post this to the sails-mongo issues forum! In the meantime the only solution appears to be to use the default MongoDB primary keys.

Related

How to extend a Content-Type Collection schema of a plugin

How can I extend a Content-Type collection schema of a plugin?, so I can add new columns.
as I want to add a column (named croppedImageUrl with string type) to the Collection File of the core plugin upload (#strapi/plugin-upload).
./src/index.js:
register({ strapi }) {
strapi.contentType('plugin::upload.file').attributes = {
...strapi.contentType('plugin::upload.file').attributes,
'workspace': {
type: 'integer',
configurable: false,
},
'user': {
type: 'integer',
configurable: false,
}
}
},

Sequelize: Virtual column is not returned in query results

I can't get this very simple virtual column to work (surnameName). It is not returned in query results, but it does not throw any error either.
My model (I removed irrelevant fields):
const Person = connectionPool.define('person', {
ID: {
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
name: Sequelize.STRING,
surname: Sequelize.STRING,
surnameName: {
type: Sequelize.VIRTUAL(Sequelize.STRING, ['surname', 'name']),
get() {
return this.getDataValue('surname') + ' ' + this.getDataValue('name');
}
}
});
This is how I query the model:
const cfg = {
where: {},
limit: 10,
raw: false, // tried with and without this line
attributes: ['surnameName']
}
models.Person.findAll(cfg)
.then(results => {
console.log(results[0]);
})
And this is what I get in the console log:
person {
dataValues: { surname: 'Baggins', name: 'Frodo' }, // all other fields are autoexcluded by Sequelize
...
_options:
{ isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
raw: true, // is true even if I set 'raw' to false in findAll options
attributes: [ 'surnameName', 'surname', 'name' ] // <= surnameName is there!
}
}
Virtual column is not returned in the results, however the logged instance shows that the internal _options.attributes array does contain the field, so Sequelize somehow acknowledges that it should be added. I tried explicitly turning raw=false, as I read that raw excludes virtual columns, but it has no effect. The results are definitely not raw.
What can be wrong here? Any help will be appreciated!
It is possible to hide properties javascript object. Here is an example
function Person(fName, lName) {
this.fName = fName;
this.lName = lName;
Object.defineProperties(this, {
fullName: {
get : function () {
return this.fName + " " + this.lName;
}
}
});
}
const ratul = new Person("Ratul", "sharker");
console.log(ratul);
console.log(ratul.fullName);
Look closely that console.log(ratul) does not print fullName, but fullName is sitting here, returning it's value seen in console.log(ratul.fullName).
Similar thing can be found in this answer.

Sequelize how to make a join request?

I'm trying to make joined queries with Sequelize.
That's my db :
What I need is to select all of my relations and get this kind of result:
[
{
id: 1,
State: true,
FK_User: {
id: 2,
Name: "my name"
},
FK_Team: {
id: 3,
Name: "team name"
}
},
...
]
But today I've got this result:
[
{
id: 1,
State: true,
FK_User: 2,
FK_Team: 3
},
...
]
For each of my relations, I've go to do another request to get datas ...
So I putted a look in this Stack and in the doc.
Then I made this code :
let User = this.instance.define("User", {
Name: {
type: this.libraries.orm.STRING,
allowNull: false
}
});
let Team = this.instance.define("Team", {
Name: {
type: this.libraries.orm.STRING,
allowNull: false
}
});
let Relation = this.instance.define("Relation", {
State: {
type: this.libraries.orm.BOOLEAN,
allowNull: false,
defaultValue: 0
}
});
Relation.hasOne(User, {as: "FK_User", foreignKey: "id"});
Relation.hasOne(Team, {as: "FK_Team", foreignKey: "id"});
With this code, I haven't got any relation between tables... So I added theses two lines. I don't understand why I need to make a two direction relation, because I don't need to access Relation From User and Team ...
User.belongsTo(Relation, {foreignKey: 'FK_User_id'});
Team.belongsTo(Relation, {foreignKey: 'FK_Team_id'});
When I do that, I've a FK_User_id in the User table and a FK_Team_id in the Team table ... I don't know how to make this simple relation and get all I need with my futur request and the include: [User, Team]} line.
User.hasOne(Relation);
Team.hasOne(Relation);
Relation.belongsTo(Team);
Relation.belongsTo(User);
This code seems to work.
I don't know why ...
Here your associations are setup correctly you can join it with include :
Relation.findAll({
where : {
state : true
}
include:[
{
model : User
},
{
model : Team
}
]
})

cant insert record with reference to another record

I have two models: platform and place (platform and place on platform)
platform
{
name: {
required: true,
unique: true,
type: String,
empty: false
},
description: {
required: false,
type: String,
empty: true
}
}
place
{
name: {
required: true,
type: String,
empty: false
},
platform: new Mongoose.Schema({
type: Mongoose.Schema.Types.ObjectId,
ref: PlatformSchema
})
}
The name of platform must be unique. First, I generate list of platforms. Then trying generate list of places on this platforms and receive error.
WriteError({
"code": 11000,
"index": 1,
"errmsg": "E11000 duplicate key error collection: test.places index: platform.ref.name_1 dup key: { : null }",
"op": {
"_id": "5b7ea477798f9c41f81c0234",
"name": "top",
"platform": {
"_id":"5b7ea41b878b4a41abcfc952"
}
}
})
Receive it until unique index for "name" field exists in platform schema.
I try insert place many ways:
PlaceRecord.insertMany([
{
name: "top",
platform: platformDocumentInstance
}
])
or
PlaceRecord.insertMany([
{
name: "top",
platform: platformDocumentInstance
}
])
or
PlaceRecord.insertMany([
{
name: "top",
platform: platformDocumentInstance
}
])
But result is same one. Note first record of place success inserted, but next record of place throw the exception. Please help.
It seems the document that you are inserting first has inserts null as platform.ref.name and when you insert second document your index platform.ref.name_1 fails because there is already a record with null.

Sails JS Waterline join of multiple models

Hi i'm trying to join multiple tables with populate method, i googled and couldn't find
efficient way of doing it, i do not want to query db several times to build the result, is it possible to solve it with sails version "~0.10.0-rc7" i'm building quit big project with more then hundred of tables.
var co = {
adapter: 'someMysqlServer',
migrate:'safe',
autoCreatedAt: false,
autoUpdatedAt: false,
autoPK:false,
attributes:{
id:{
type:"int",
primaryKey: true,
autoIncrement: true
},
code:"string",
priority :"int",
co_group_c_id :"int",
timezone_c_id :"int",
lang_c_id :"int",
currency_c_id :"int",
name_used :"string",
name_official :"string",
co_tax_no :"int",
co_vat_no :"int",
co_vat_reg :"int",
co_reg_record :"string",
co_representative :"string",
co_addresses:{
collection: "co_address",
via: "co_user_id"
},
}
};
module.exports = co;
var co_address = {
adapter: 'someMysqlServer',
migrate:'safe',
autoCreatedAt: false,
autoUpdatedAt: false,
autoPK:false,
attributes: {
id:{
type:"int",
primaryKey: true,
autoIncrement: true,
},
address_c_id:"int" ,
address_street_first: "string",
address_street_second: "int",
address_street_third: "int",
address_postalcode: "string",
address_city: "string",
co_user_id: {
model: 'co_user'
},
co_id: {
model: 'co'
},
co_address_opening_hours:{
collection: "co_address_opening_hours",
via: "co_address_id"
},
}
};
module.exports = co_address;
var co_address_opening_hours = {
adapter: 'someMysqlServer',
migrate:'safe',
autoCreatedAt: false,
autoUpdatedAt: false,
autoPK:false,
attributes:{
id:{
type:"int",
primaryKey: true,
autoIncrement: true
},
day_c_id: "int",
time_from: "datetime",
time_to :"datetime",
co_address_id: {
model: 'co_address'
}
}
};
module.exports = co_address_opening_hours;
//controller
get_co:function(req,res){
co.find()
.populate("co_addresses")
.populate("co_address_opening_hours")
.exec(function(e, company) {
if(e) console.log(e);
console.log(company);
res.json(company);
})
In SailsJS 0.10+ you can use model associations to do database joins. You can read more about them here: http://sailsjs.com/documentation/concepts/models-and-orm/associations
Basically you first define an association in your model;
var someModel = {
attributes: {
name: {
type: 'text'
}
}
};
var someOtherModel = {
attributes: {
name: {
type: 'text'
},
associationProp: {
model: 'someModel'
}
}
};
In the code above someOtherModel contains association (relation) to someModel. To do a join query you can use .populate() method. For example retrieve all someOtherModel entities and populate associative properties;
someOtherModel.find().populate('associationProp').exec(...);
For MySQL and PSQL adapters there's also .query() method available where you can write some hand written SQL queries to be executed (this also works in sails <0.10);
Model.query(<sql query>, <optional data>, callback);

Resources