Sails js One-to-Many Relationship with custom column names - sails.js

Faced serious problems here with Sails Js.
So, i have one-to-many relationship as described below (taken from official sails documentation):
// myApp/api/models/User.js
// A user may have many pets
module.exports = {
attributes: {
firstName: {
type: 'string',
columnName: "first_name"
},
lastName: {
type: 'string',
columnName: "last_name"
},
// Add a reference to Pets
pets: {
collection: 'pet',
via: 'owner'
}
}
};
and dependent model:
// myApp/api/models/Pet.js
// A pet may only belong to a single user
module.exports = {
attributes: {
breed: {
type: 'string'
//column name will be 'breed' by default
},
typeProperty: {
type: 'string',
columnName: "type_property"
},
nameProperty: {
type: 'string',
columnName: "name_property"
},
// Add a reference to User
owner: {
model: 'user'
}
}
};
When I'm calling in the code following query
User.find()
.populate('pets')
.exec(function(err, users) {
if(err) // handle error
// The users object would look something like the following
[{
id: 123,
firstName: 'Foo',
lastName: 'Bar',
pets: [{
id: 1,
// !! Only this property is loaded !!
breed: 'labrador',
// !! This property is NOT loaded !!
typeProperty: undefined,
// !! This property is NOT loaded !!
nameProperty: undefined,
user: 123
}]
}]
});
Basically, seems that sails (waterline if to be specific) is not mapping back properties, which have custom "columName" specified and differs from property name (ex. "typeProperty" stored in type_property column).
Has anyone faced this kind of problem?

In fact, I faced this problema. The property "columnName" is not working. Seems like Sails doesn't prioritizes this property over it's model's convention naming.
Try to change the model attribute name to be equal your database property.
type_property: {
type: 'string'
},
this should make your attributes to be populated. Worked here.
Column name works fine when the attribute in question is a foreign key.

Related

How to require properties only on create entity in loopback4

I have a model with required properties but are only required on create, on update only the id property es required.
This is my model example:
#model()
export class MyModel extends Entity {
#property({
type: 'string',
required: true
})
name: string;
#property({
type: 'string',
id: true,
})
id: string;
}
On Mongoose schemas i can define a context to validate params but on Loopback 4 documentation i can't found nothing like this to solve this problem
Have you tried excluding the id property from the #requestBody decorator of the parameter of the request controller
#requestBody({
content: {
'application/json': {
schema: getModelSchemaRef(Model, {exclude: ['id']}),
},
},
}
Add this as a parameter to the method of the controller
Or
YOu can create a custom schema for the request body something like
const RequestSchema = {
type: 'object',
required: ['name'],
properties: {
name: {
type: 'string',
},
id: {
type: 'string',
},
},
};
export const RequestBody = {
required: true,
content: {
'application/json': {schema: RequestSchema},
},
};
See how only the name is required and Id is not in the RequestSchema Object
then pass it to the controller method as
#requestBody(RequestSchema)
Hopefully, this shall work.
Write me if this also not fixes the problem.
Thanks

addToCollection and set intermediate table column values as well

I am using Sails v1.1 -
Following the example from the "Through" associations on sails - https://sailsjs.com/documentation/concepts/models-and-orm/associations/through-associations
They defined a "through" association as basically a custom model. So this really isn't "through", it's just controlling the join table for the many to many relation.
So in the intermediate model, I added a custom attribute of isTyping seen below.
Is it possible to add to collection and set this intermediate value at same time?
For exmaple pseudocode with setIntermediate:
User.addToCollection(userId, 'pets', petId).setIntermediate('isTyping', true);
So following the example on the docs:
myApp/api/models/User.js
module.exports = {
attributes: {
name: {
type: 'string'
},
pets:{
collection: 'pet',
via: 'owner',
through: 'petuser'
}
}
}
myApp/api/models/Pet.js
module.exports = {
attributes: {
name: {
type: 'string'
},
color: {
type: 'string'
},
owners:{
collection: 'user',
via: 'pet',
through: 'petuser'
}
}
}
myApp/api/models/PetUser.js
module.exports = {
attributes: {
owner: {
model:'user'
},
pet: {
model: 'pet'
},
// I ADDED THIS INTERMEDIATE COLUMN NAME in the join table
isTyping: {
type: 'boolean',
defaultsTo: false
}
}
}
I don't know if this is right, but the way to do this is instead of using Pet.addToCollection(petId, 'owners', userId)/User.addToCollection(userId, 'pets', petId) or Pet.removeFromCollection(petId, 'owners', userId)/User.removeFromCollection(userId, 'pets', petId), is to instead do:
PetUser.create({ owner: userId, pet: petId, isTyping: true }).populate('user').populate('pet')
I'm not sure if right, and this doesn't support the array argument that addToCollection/removeFromCollection does. And you also have to massage the data in order to get a list of owners/pets with the pivot attribute of isTyping.

Waterline: Create or update a populate record

My question is basic but I can not find an answer in the documentation. I have two models: 'Person' and 'Location' being associated One-to-one. I want to create or update 'populated child records' in the Location collection.
let person = await Person.findOne({ phone: inputs.phone }).populate('reside');
Well return
{ reside: [],
createdAt: 1540081110195,
updatedAt: 1540331824622,
id: '5bcbc5d609618e2cfbe64883',
phone: '+42424242',}
I want to create new location record (when they do not exist) or update if their exist. I try
let location = await Location.update({ id: person.reside.id })
.set({city: inputs.city,
street: inputs.street,
}).fetch;
But it does not work when no record has been created yet.
model/Person.js
phone: {
type: 'string',
unique: true,
},
reside: {
collection:'location',
via: 'owner'
},
models/Location.js
city: { type: 'string' },
street: { type: 'string' },
owner:{
model:'person',
unique: true
}
I use action2
I finally found here methods .addToCollection(), .removeFromCollection(), or .replaceCollection() to modify the populated values of a particular record or set of records. It does not seem to be the most appropriate place in the doc to talk about it

Sails v1.0: error while using custom primary key with mongo

I'm giving a try to the beta version of SailsJS (v1.0.0-32) and I'm having some issues while configuring a custom id. Bellow you'll find my current configuration:
The modelExample.js
module.exports = {
attributes: {
id:{
type: 'string',
columnName: '_id'
},
attr: {
type: 'number'
}
}
}
The model config config/models.js
attributes: {
createdAt: { type: 'number', autoCreatedAt: true, },
updatedAt: { type: 'number', autoUpdatedAt: true, },
id: { type: 'string', columnName: '_id' },
}
The element trying to be inserted:
{id:"600000", attr:40}
The error I get when trying to create a record with an attribute "id" included in the element trying to be created:
AdapterError: Unexpected error from database adapter: Invalid primary key value provided for `id`. Cannot interpret `600000` as a Mongo id.
(Usually, this is the result of a bug in application logic.)
Seems that mongo does not like the string 600000 as an id, but I'm not sure if maybe I'm misunderstanding something related to ids in mongo. In the old version of sails, I never had this issue since the id override was straightforward.
For more information, the sails-mongo adapter version is: "sails-mongo": "^1.0.0-5"
In order to use non-ObjectID primary keys with sails-mongo in Sails 1.0, you have to set dontUseObjectIds: true in your model, for example:
// api/models/User.js
module.exports = {
dontUseObjectIds: true,
attributes: {
id: { type: 'number', columnName: '_id' }, // <-- still need to set `columnName`!
name: { type: 'string' },
...etc...
}
}
This is implemented as of sails-mongo v1.0.0-7.

populate additional information of the 'through' table in sails

I have two models and there is many to many association in between them(I am using sails.js framework). I have added the addition field in the association table. I want to populate that addition field. How do I achieve this? My models are given below:
//Store.js file
module.exports = {
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
name: "string",
slug: "string",
imageURL: "string",
termsAndConditions: "string",
link: "string",
productID: {
collection: 'product', //This is for association with the product model
via: 'storeID',
through: 'price'
}
}
};
Below is my Product.js file
//Product.js
module.exports = {
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
name: 'string',
storeID: {
collection: 'stores',
via: 'productID', //This is for association with the Store model
through: 'price'
}
}
};
And below is my through model Price.js
module.exports = {
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
storeID: {
model: 'stores'
},
productID: {
model: 'product'
},
price: 'integer' //I want to populate this additional field when calling api '/product' or '/store'
}
};
How to populate the additional field price of Price table from calling the api '/product' or '/store'?
Inside the callback function after populating (exec or then depending on your implementation) Find the record in the price table and perform update on that record to change the value of price from null to whatever value you want. Share your implementation code for more detailed answer.