I have mongodb sitting behind an existing API and want to migrate the API to use sailsjs.
The data structure isn't anything crazy - just standard stuff using default mongodb ObjectIds as primary keys.
Will I be able to use this existing db with sails by just wiring up sails models? Do I need to specify the _id field? And, if so, what datatype should I use?
E.g. Existing mongodb with user collection with the following schema:
_id
name
fname
lname
age
Can I just wire up using something like the following for it to work?:
// User.js
var User = {
attributes: {
name: {
fname: 'STRING',
lname: 'STRING'
},
age: 'INTEGER'
}
};
module.exports = Person;
First: you dont have to define _id (waterline do this for you)
Waterline wants to help you using the same Functions and Models for all types of databases. A "Sub-Field" is not supported in mysql for example. So this don't work.
You can do this:
// User.js
var User = {
attributes: {
name: 'json',
age: 'integer'
}
};
module.exports = User;
If you want to validate "name" you can add your own validation:
// User.js
var User = {
types: {
myname: function(json){
if(typeof json.fname == "string" && typeof json.lname == "string"){
return true;
}else{
return false;
}
}
},
attributes: {
name: {
type: "json",
myname: true
},
age: 'integer'
}
};
module.exports = User;
Related
I have a User model with a schema that I would like to validate an array of multiple friends by their id's. The portion of the schema that is supposed to do this is:
friends: {
type: [mongoose.SchemaTypes.ObjectId],
},
Then, when I try to add a friend with an id value and populate it inside the API endpoint, it adds the id to the database, but does not populate it. Here is the code:
if (method === "POST") {
const userId = getIdFromCookie(req);
try {
const newFriend = {
friends: req.body.friend
};
const updatedUser = await User.findByIdAndUpdate(userId, newFriend, {new: true})
const popUser = await User.findById(userId).populate("friends")
res.status(200).json({success: true, data: updatedUser});
} catch (error) {
res.status(400).json({success: false});
}
} else {
res.status(400).json({error: "This endpoint only supports method 'POST'"})
}
I want to know how I can add a friend's id to the database, whilst simultaneously populating it in the same endpoint.
The user schema is missing the ref field.
Example from the docs:
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
Without the ref, Mongoose doesn't know where to lookup the ObjectId.
Inside my MongoDB repositories, entities have an _id: ObjectID type to be handled properly. However, I would like my domain entities to have a simple id: string attribute to avoid any dependencies on any database or framework. The solution I came up with so far looks as follows:
export interface Book {
id: string;
title: string;
}
// A MongodbEntity<Book> would now have an _id instead of its string id
export type MongodbEntity<T extends { id: string; }> = Omit<T, 'id'> & { _id: ObjectID; };
In my repository this would work:
async findOneById(id: string): Promise<Book | null> {
const res = await this.collection.findOneById({_id: new ObjectId(id)});
return res ? toBook(res) : null;
}
function toBook(dbBook: MongodbEntity<Book>): Book {
const {_id, ...rest} = dbBook;
return {...rest, id: _id.toHexString() };
}
What doesn't work is to make this behavior generic. A converter function like this:
function toDomainEntity<T extends {id: string}>(dbEntity: MongoDbEntity<T>): T {
const {_id, ...rest} = dbEntity;
return {...rest, id: _id.toHexString() };
}
leads to an error described here.
What I am looking for is either a working solution for the generic toDomainEntity function or a different (generic) approach that would let me decouple my domain entity types from MongoDB's _id: ObjectID type.
I am trying to fetch all users from a MongoDB database. However for some reason recently the request did not fetch anything.
Here is the code in which I try to fetch the data:
app.get('/api/allusers', (req, res) => {
Employee.find()
.then(rettrievedData => {
res.json(rettrievedData)
});
});
Here is the mongoose model:
const mongoose = require('mongoose');
const employeeSchema = mongoose.Schema({
name: { type: String },
surName: { type: String },
mail: { type: String },
phone: { type: String },
});
module.exports = mongoose.model('Employee', employeeSchema, 'employee.employees');
Here is the code for connecting to Mongo
mongoose.connect("mongodb+srv://Kiril:xxxxxxxxxxxxx#cluster0-owdfy.mongodb.net/employee?retryWrites=true&w=majority")
.then(() => {
console.log("Connected")
})
Also I have checked that there is data in the database, but for some reason the Employee.find() does not retrieve anything. What can be reason?
Thanks in advance.
why you are adding 'employee.employyes' when you creating your model
try to export the model without it
module.exports = mongoose.model('Employee', employeeSchema)
or better
exports.Employee = mongoose.model('Employee', employeeSchema)
and require it where you want to use it
const Employee = require('path to the schema file')
I have this model that is taken from this sails documentation page
module.exports = {
attributes: {
// Primitive attributes
firstName: {
type: 'string',
defaultsTo: ''
},
lastName: {
type: 'string',
defaultsTo: ''
},
// Attribute methods
getFullName: function (){
return this.firstName + ' ' + this.lastName;
}
}
};
What I expect when I call my auto generated restful api (using blueprint)
localhost:port/resourceName
is
{"firstName":"john", "lastName":"Doe", "getFullName": "john Doe"}
instead what I am getting is this
{"firstName":"john", "lastName":"Doe"}
any ideas?
I already checked other posts such as this one github.
sails version: 0.11.4
Thanks a lot :)
If you want the custom attribute to be serialised you can override the default toJSON instance method:
toJSON: function() {
var obj = this.toObject();
obj.fullName = this.getFullName();
return obj;
}
I would like to add a category and then if successed, push it's ref to user' collection. That's how I'm doing this:
That's mine "dashboard.js" file which contains categories schema.
var users = require('./users');
var category = mongoose.model('categories', new mongoose.Schema({
_id: String,
name: String,
ownerId: { type: String, ref: 'users' }
}));
router.post('/settings/addCategory', function(req, res, next) {
console.log(req.body);
var category_toAdd = new category();
category_toAdd._id = mongoose.Types.ObjectId();
category_toAdd.name = req.body.categoryName;
category_toAdd.ownerId = req.body.ownerId;
category.findOne({
name: req.body.categoryName,
ownerId: req.body.ownerId
}, function(error, result) {
if(error) console.log(error);
else {
if(result === null) {
category_toAdd.save(function(error) {
if(error) console.log(error);
else {
console.log("Added category: " + category_toAdd);
<<<<<<<<<<<<<<<<<<<THE CONSOLE LOG WORKS GOOD
users.categories.push(category_toAdd);
}
});
}
}
});
Here is my "users.js" file which contains "users" schema.
var categories = require('./dashboard');
var user = mongoose.model('users', new mongoose.Schema({
_id: String,
login: String,
password: String,
email: String,
categories: [{ type: String, ref: 'categories' }]
}));
So, the category add proccess works well and I can find the category in database. The problem is when I'm trying to push the category to user.
This line:
users.categories.push(category_toAdd);
I get this error:
Cannot read property "push" of undefined.
I need to admit once more that before that pushing there is console.log where the category is printed properly.
Thanks for your time.
The users object is a Mongoose model and not an instance of it. You need the correct instance of the users model to add the category to.
dashboard.js
...
category_toAdd = {
_id: mongoose.Types.ObjectId(),
name: req.body.categoryName,
ownerId: req.body.ownerId
};
// Create the category here. `category` is the saved category.
category.create(category_toAdd, function (err, category) {
if (err) console.log(err);
// Find the `user` that owns the category.
users.findOne(category.ownerId, function (err, user) {
if (err) console.log(err);
// Add the category to the user's `categories` array.
user.categories.push(category);
});
});