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.
Related
on mongo db compass I'd like to use a validation schema but on of my properties is an enum, depending on this field another field can be toggled I was able to do this using JSON schema but it dosen't seems to be working on mongoDB compass why ?
{
type: 'object',
properties: {
type: {
enum: ['teacher', 'student']
},
firstname: {
type: 'string',
},
lastname: {
type: 'string',
},
login: {
type: 'string',
},
pwd: {
type: 'string'
},
"if": {"properties": {"type": {"const": "student"}}},
"then": {"properties": {classes: {type: "array"}}}
},
required: [
'type',
'firstname',
'lastname',
'login',
'pwd',
],
};
No.
The MongoDB documentation indicates that it is using draft 4:
JSON Schema object is formatted according to draft 4 of the JSON Schema standard.
The JSON Schema site says these conditionals are new in draft 7:
New in draft 7 if, then and else keywords
let validator = new Validator(req.body, {
password: "requiredIf:is_login_user,1",
});
I have an association between Client and Budget as follows:
//Client.js
module.exports = {
primaryKey: 'id',
attributes: {
id: {
type: 'number',
unique: true,
autoIncrement: true
},
name: {
type: 'string'
},
phone: {
type: 'string',
unique: true
},
email: {
type: 'string',
unique: true
},
budgets: {
collection: 'budget',
via: 'client'
},
}
};
// Budget.js
module.exports = {
primaryKey: 'id',
attributes: {
id: {
type: 'number',
unique: true,
autoIncrement: true
},
client: {
model: 'client'
},
budgetItems: {
type: 'json'
}
}
};
So, POST is working for both entities so I can create both of them, but:
GET /budget/1
returns the budget and the id of the associated client.
GET /budget/1/client
returns the client id without populating(as i've seen in documentation it should be populated).
GET /client/1
returns the client attributes and there is not a field related with budgets.
GET /client/1/budgets
returns 404 NOT FOUND
I'm following this and this official documentation
So what I could be missing?
Is just generating one direction associations, and I've compared with official documentation and third party examples and my code looks fine.
Thanks in advance!
Update:
I still looking for troubles and if I run sails with --silly option it shows there is the following route available:
Binding route :: get /client/:parentid/budgets POLICY: localize
Binding route :: get /client/:parentid/budgets POLICY: isauth
Binding route :: get /client/:parentid/budgets BLUEPRINT: populate
but if I try to access returns a 404 Not Found and console shows the following error, thrown by populate.js from Sails core code:
verbo: In populate blueprint action: Specified parent record (1)
does not have a budgets.
Update2:
Debugging with sails console I've seen the association is generated properly. Given Client.findOne({id: 1}).populate('budgets').then((client)=>{console.log(client)}) print the client attributes and the associated Budgets but still return 404 Not Found when: GET /client/1/budgets
I have created quick demo and it seems working fine for me.
For demo I have used sails version 1.2.2 and sails-disk as database and there is some minor difference in Model attributes as below
Client.js
module.exports = {
attributes: {
name: {
type: 'string'
},
phone: {
type: 'string',
unique: true,
required: true
},
email: {
type: 'string',
unique: true,
required: true
},
budgets: {
collection: 'Budget', // <<== B is capital here
via: 'client'
},
},
};
Budget.js
module.exports = {
attributes: {
client: {
model: 'Client' // <<== C is capital here
},
budgetItems: {
type: 'json'
}
},
};
Let me know if this is helpful
thanks to SailsJS team we've found the problem and it was related with a third party package and just had to remove it from my project.
It was sails-hook-deep-orm who's owner has been warned. I hope someone with the same issue will reach this post.
Thanks u all anyway!!
The issue is available there
I'm using js-data with the mongodb adapter js-data-mongodb. I'm running into an issue where store.findAll is only returning the _id of the record. No other fields are returned.
Here is my record in my artworks collection in mongoDB:
_id: ObjectId("59bb7ee069d99027f5219667")
uid :"599b73c285b13252e7f54161"
title: "t1"
description: "t1"
imageUrl: "this.artwork.imageUrl"
videoUrl: "this.artwork.videoUrl"
Part of my js-data store definition:
// Create a store to hold your Mappers
const store = new Container({});
// Mappers in "store" will use the MongoDB adapter by default
store.registerAdapter('mongodb', adapter, { 'default': true });
store.defineMapper('artwork', {
collection: 'artworks',
schema: artworkSchema,
idAttribute: '_id'
});
And the code in my app:
store.findAll('artwork', {uid: '599b73c285b13252e7f54161'}).then((records) => {
console.log(records);
})
The output:
[ Record { _id: '59bb7ee069d99027f5219667' } ]
What am I missing in order to get all the fields of the record returned in the response?
Thanks!
Update:
Turns out if I remove my schema definition from the mapper, the fields are returned correctly. This is my schema definition. I'm not sure where I'm going wrong here.
const artworkSchema = new Schema({
$schema: 'http://json-schema.org/draft-06/schema#',
title: 'Artwork',
description: 'Schema for Artwork records',
type: 'object',
properties: {
uid: { type: 'string' },
title: { type: 'string' },
description: { type: 'string' },
imageUrl: { type: 'string' },
videoUrl: { type: 'string' }
},
required: ['uid', 'title', 'imageUrl', 'videoUrl']
});
Argh, that was silly of me. The findAll() call was returning an array of Records, with its attributes. The console.log() wasn't showing it but I am able to get the data by using the array index (records[0].title) or using get('title') as described in the documentation.
I'm trying to create 2 user in parallel and wait for it to be created after do something else. I was trying to use:
Promise.all([User.create(usr1), User.create(usr2), User.create(usr3)]).then(function(){
console.log("\o/");
}
without luck, because User.create() do not return a Promise.
I also tried:
User.create([usr1, usr2]).then(function(){
console.log('x')
})
Error that I get:
[Error (E_VALIDATION) 1 attribute is invalid] Invalid attributes sent to undefined:
• user
• A record with that user already exists (null).
Ugly code that is working:
User.create([usr1]).then(function(){
User.create[usr2].then(function(){ console.log('x') });
});
Also work with .exec()
User.create([usr1, usr2]).exec(function(){
console.log('x')
})
How can I use Promise or just waterline to create two user?
EDIT:
1) Calling it in mocha test
Code here
attributes: {
name: {
type: 'string',
required: true
},
email: {
type: 'email',
required: true,
unique: true
},
password: {
type: 'string',
minLength: 6,
},
//Association One-to-One, but using 'collection' to mantain sync updating
employer: {
collection: 'employer',
via: 'user'
},
employee: {
collection: 'employee',
via: 'user'
},
//Google Signin ID
googleId: 'string',
//Access token from the Google Authorization Server
googleAccessToken: 'string',
resetPasswordToken: String,
resetPasswordExpires: Date,
toJSON: function() {
var obj = this.toObject();
delete obj.password;
delete obj.resetPasswordToken;
delete obj.resetPasswordExpires;
return obj;
}
},
EDIT2:
This error only happens when I use sails-disk, in sails-mongo work
I have two collections in mongodb database and model for each of them
App Model
module.exports = {
tableName: 'app',
attributes: {
_id : {
primaryKey: true,
unique: true,
type: 'string',
},
userId: {
model: 'user'
},
title: {
type: 'string',
required: true,
unique: true,
},
createdDate : 'string'
},
};
and User Model
module.exports = {
tableName: 'user',
attributes: {
id : {
primaryKey: true,
unique: true,
type: 'string',
collection: "app",
via : "userId"
},
password: {
type: 'string',
required: true
},
apps : {
collection: "app",
via : "userId"
}
},
};
When i use numeric values for join this collection, it works fine, but when i try do it with mongodb native id object, i get the empty result
How i call join query
User.find().populate('apps').exec(function(err, result) {});
You need to get rid of both the _id and id attribute definitions in your models. Waterline will handle the primary key fields for you automatically (normalizing them to id), so unless you need to change the field type, they can be safely left out. Also, I'm not sure what your intention was by adding collection and via to the id definition, but the primary key is never going to be an association.
Otherwise, your models look correct. If you get rid of those two attributes, things should work fine.