I have been working at this for the past 4 hours. I would therefore like some help. I want to access the specific values in my database, eg. as response.data.values.imglink although when adding imglink in console.log() I get undefined. I can get the general object but not the specifik values.
I have defined my Song Schema as:
const songSchema = new Schema({
values: [{
imglink: {
type: String
},
id: {
type: String
},
spotify: {
type: String,
},
soundCloud: {
type: String,
},
youtube: {
type: String,
},
appleMusic: {
type: String,
}}
],
}, {
timestamps: true,
})
As you can see values is an array of objects. People with a similiar problem on here hadn't included the correct values in their Schema, so maybe that's my problem? Although to me it looks correct. I then GET the values in my database. The JSON object usually looks something like this:
[
{
"_id": "5ffbba4dc47e847a79c9c68f",
"values": [
{
"_id": "5ffbba4dc47e847a79c9c690",
"imglink": "imagelink",
"id": "id",
"soundCloud": "soundcloudvalue",
"youtube": "youtubevalue",
"appleMusic": "applemusicvalue",
"spotify": "spotifyvalue"
}
]
}
]
I call it by this function, which is supposed to print out the individual values:
const getAllSongs = () => {
axios.get('http://localhost:5000/songs/'+id)
.then(function (response) {
console.log(response); // returns an object
console.log(response.data.values.imglink); // returns an object
})
.catch(function (error) {
// handle error
console.log(error);
})
}
I have an Express route object that allows me to access a song by it's id as GET http://localhost:5000/songs/id in the VS-code HTTP client (similiar to postman):
router.get(`/:id`, function(req, res) {
return Song.find(
{"values.id": req.params.id}
).then(function(song) {
// return orders when resolved
res.send(song);
console.log(id);
res.json('works yesss');
})
.catch(function (err) {
// handle error
res.status(400).json('Error: '+err)
})
});
Here are some popular solutions I have tried:
Wrapping response in JSON.stringify() doesn't work.
toObject() and toJSON() don't work either as they aren't defined when I use them.
the _doc hack doesn't work either.
I have tried looking at the Schema which is where I think the problem is. The POST-request adds the right data, the GET-request goes through I just can't acces the specific values.
I hope you have the time to help, thanks. I will be extremely grateful. And of course let me know if you have any questions.
the result of find() is a Array so to access the desired key, if length of result Array is one, to access the desired key is response.data[0].values[0].imglink.
note: the values key is a array of obejct
If the array size is more than one, you want to see the result, you can use map()
if it's not worked, using lean() like this
router.get(`/:id`, function(req, res) {
return Song.find(
{"values.id": req.params.id}
).lean().then(function(song) {
// return orders when resolved
res.send(song);
console.log(song[0].values[0].imglink); // type of song is array of object [] and values is array
res.json('works yesss');
})
.catch(function (err) {
// handle error
res.status(400).json('Error: '+err)
})
});
I have been trying yesterday and still continuing today to figure out how to create a nodejs delete method so I can delete data from database based on ID.
I have tried different code from google/youtube/stackoverflow etc but nothing has worked so far.
The error I have with this code is that data.query is not a function. Data is a variable on my code.
If anyone has any idea how to fix please help.
app.js
app.delete('/zoom/:id', function(req, res) {
data.query('delete from', [req.params.id]);
res.render('deleted')
});
data.js
var Data = sequelize.define('data', {
subject: Sequelize.STRING,
MEETINGID: Sequelize.STRING,
Password: Sequelize.STRING
});
Sequelize destroy method seems like a suitable one. E.g.
app.delete("/zoom/:id", function (req, res) {
data.destroy({
where: {
// criteria
},
});
res.render("deleted");
});
To set a criteria which i suitable for your situation, you will need to take a look at sequelize syntax. I found some examples and may be you can modify them to your needs. Depending on your database structure.
where: {
'$car.id$': 2
},
where: {
furniture_type: 'leather'
},
where: {
id: {
$notLike: { $any: someValue }
}
},
I have a schema that has an id field that is set to a string. When I use collection.find({id: somenumber}) it returns nothing.
I've tried casting somenumber to a string and to a number. I've tried sending somenumber through as a regex. I've tried putting id in quotes and bare... I have no idea what's going on. Any help and input would be appreciated.
Toys.js
var Schema = mongoose.Schema;
var toySchema = new Schema( {
id: {type: String, required: true, unique: true},
name: {type: String, required: true},
price: Number
} );
My index.js is as such
app.use('/findToy', (req, res) => {
let query = {};
if (req.query.id)
query.id = req.query.id;
console.log(query);
// I've tried using the query variable and explicitly stating the object as below. Neither works.
Toy.find({id: '123'}, (err, toy) => {
if (!err) {
console.log("i'm right here, no errors and nothing in the query");
res.json(toy);
}
else {
console.log(err);
res.json({})
}
})
I know that there is a Toy in my mongoDB instance with id: '123'. If I do Toy.find() it returns:
[{"_id":"5bb7d8e4a620efb05cb407d2","id":"123","name":"Dog chew toy","price":10.99},
{"_id":"5bb7d8f7a620efb05cb407d3","id":"456","name":"Dog pillow","price":25.99}]
I'm at a complete loss, really.
This is what you're looking for. Visit the link for references, but here's a little snippet.
For the sake of this example, let's have a static id, even though Mongo creates a dynamic one [ _id ]. Maybe that what is the problem here. If you already a record in your DB with that id, there's no need for adding it manually, especially not the already existing one. Anyways, Drop your DB collection, and try out this simple example:
// Search by ObjectId
const id = "123";
ToyModel.findById(id, (err, user) => {
if(err) {
// Handle your error here
} else {
// If that 'toy' was found do whatever you want with it :)
}
});
Also, a very similar API is findOne.
ToyModel.findOne({_id: id}, function (err, toy) { ... });
I have a rest api resource that accepts a JSON post. Example:
{
"location": {
"coordinates": [
-122.41941550000001,
37.7749295
]
}
The coordinates are then collected from the request by Express:
module.exports.create = function(req, res, next) {
var coordinates = req.body.location.coordinates;
....
These are then submitted to a Mongoose model. I am writing tests against this where the location.coordinates is missing e.g.
{
"foo": {
"bar": [
-122.41941550000001,
37.7749295
]
}
This then fails within the validation section of the Model with :
locationSchema.path('location.coordinates').validate(function(coordinates){
^
TypeError: Cannot call method 'validate' of undefined
So my question is how would I validate that the input is correct? Should this be done in the route before getting to the model, or should it be done in the model? Any examples of how would also be appreciated.
For reference the Mongoose model looks something like:
var locationSchema = new Schema({
userid: { type: Number, required: true },
location: {
type: [{
type: "String",
required: true,
enum: ['Point', 'LineString', 'Polygon'],
default: 'Point'
}], required: true,
coordinates: { type: [Number], required:true }
},
create_date: { type: Date, default: Date.now }
});
locationSchema.path('location.coordinates').validate(function(coordinates){
...
}, 'Invalid latitude or longitude.');
My typical approach is to introduce a service layer in between the routes and the model, and that's where the validation happens. Don't think "service" in the "web service" sense; it simply provides an abstraction level around a given domain. This has the following benefits:
It gives you a common abstraction for dealing with persisted and/or external data. That is, whether you're interacting with data from Mongoose or an external web service, all of your route logic can simply interact with a consistent interface.
It provides sound encapsulation around persistence details, allowing you to swap out the implementation without effecting all of your routes.
It allows you to re-use code with non-route consumers (such as an integration test suite).
It provides a good layer for mocking (for use with unit tests, for example).
It provides a very clear "validation and business logic happens here" layer, even when your data is spread across several different databases and/or backend systems.
Here's a simplified example of what that might look like:
location-service.js
var locationService = module.exports = {};
locationService.saveCoordinates = function saveCoordinates(coords, cb) {
if (!isValidCoordinates(coords)) {
// your failed validation response can be whatever you want, but I
// like to reserve actual `Error` responses for true runtime errors.
// the result here should be something your client-side logic can
// easily consume and display to the user.
return cb(null, {
success: false,
reason: 'validation',
validationError: { /* something useful to the end user here */ }
});
}
yourLocationModel.save(coords, function(err) {
if (err) return cb(err);
cb(null, { success: true });
});
};
some-route-file.js
app.post('/coordinates', function(req, res, next) {
var coordinates = req.body.location.coordinates;
locationService.saveCoordinates(coordinates, function(err, result) {
if (err) return next(err);
if (!result.success) {
// check result.reason, handle validation logic, etc.
} else {
// woohoo, send a 201 or whatever you need to do
}
});
});
I've applied this structure to 3 or 4 different web apps and APIs at this point, and have grown quite fond of it.
In my opinion the validation should occur at the very beginning, on the client at first, then in the route.
There's not much interest in passing around invalid data, using resources for nothing, so the sooner you flag it as invalid, the sooner you free the resources.
to check existence of your coordinates, you can use :
if(req.body.location.coordinates){
//do your thing
}
I am looking for an example nodejs app that uses the sequelize ORM.
My main concern is that it seems next to impossible to define your models in separate js files if those models have complex relationships to one another because of require() dependency loops. Maybe people define all their models in one file that is very very long?
I am mainly interested in how the models are defined and use through out the app. I would like to have some validation that what i am doing on my own is the "good" way to do things.
The short story
The trick in this case is not to initialize the model in the file but just to provide the necesary information for its initialization and let a centralized module take care of the models setup and instantiation.
So the steps are:
Have several Model files with data about the model, like fields, relationships and options.
Have a singleton module which loads all those files and setup all the model classes and relationships.
Setup your singleton module at the app.js file.
Get the model classes from the singleton module do not use require on your model files, load the models from the singleton instead.
The longer story
Here is a more detailed description of this solution with the corresponding source code:
http://jeydotc.github.io/blog/2012/10/30/EXPRESS-WITH-SEQUELIZE.html
EDIT: This is a very old answer! (read down for info)
It's old and limited in many ways!
First, as #jinglesthula mentioned in comments (and I experienced it too) - there are problems with requiring those files. It's because require doesn't work the same way as readdirSync!
Second - you are very limited in relations - the code doesn't provide options to those associations so you are UNABLE to create belongsToMany as it needs through property. You can make the most basic assocs.
Third - you are very limited in model relations! If you read closely the code, you will see that relations is an Object instead of an Array, so if you want to make more than one associations of the same type (like having two times belongsTo) - you cannot!
Fourth - You don't need that singleton thingy. Every module in nodejs is singleton by itself, so all this makes is pretty complex for no reason.
You should see Farm's answer! (The link to the article is broken, but I'll fix it with this official sample from sequelize: https://github.com/sequelize/express-example/blob/master/models/index.js - you can browse the whole project to get an idea of what's going on).
p.s.
I'm editing this post as it's so upvoted that people won't even see any new answers (as I did).
Edit: Just changed the link to a copy of the same post, but in a Github Page
SequelizeJS has a article on their website which solves this problem.
Link is broken, but you can find the working sample project here and browse it. See edited answer above to see why this is a better solution.
Extract from article:
models/index.js
The idea of this file is to configure a connection to the database and to collect all Model definitions. Once everything is in place, we will call the method associated on each of the Models. This method can be used to associate the Model with others.
var fs = require('fs')
, path = require('path')
, Sequelize = require('sequelize')
, lodash = require('lodash')
, sequelize = new Sequelize('sequelize_test', 'root', null)
, db = {}
fs.readdirSync(__dirname)
.filter(function(file) {
return (file.indexOf('.') !== 0) && (file !== 'index.js')
})
.forEach(function(file) {
var model = sequelize.import(path.join(__dirname, file))
db[model.name] = model
})
Object.keys(db).forEach(function(modelName) {
if (db[modelName].options.hasOwnProperty('associate')) {
db[modelName].options.associate(db)
}
})
module.exports = lodash.extend({
sequelize: sequelize,
Sequelize: Sequelize
}, db)
I've create a package sequelize-connect to help people deal with this issue. It follows the Sequelize suggested convention here: http://sequelize.readthedocs.org/en/1.7.0/articles/express/
Additionally it also functions a bit more like Mongoose in terms of its interface. It allows you to specify a set of locations where your models are located and also allows you to define a custom matching function to match your model files.
The usage is basically like this:
var orm = require('sequelize-connect');
orm.discover = ["/my/model/path/1", "/path/to/models/2"]; // 1 to n paths can be specified here
orm.connect(db, user, passwd, options); // initialize the sequelize connection and models
Then you can access the models and sequelize like so:
var orm = require('sequelize-connect');
var sequelize = orm.sequelize;
var Sequelize = orm.Sequelize;
var models = orm.models;
var User = models.User;
Hopefully this helps someone out.
I started using Sequelize in Express.js app. Soon enough ran into issues of the nature you're describing. Maybe I did not quite understand Sequelize, but to me doing things more than just selecting from one table wasn't really convenient. And where ordinarily you would use select from two or more tables, or a union in pure SQL, you would have to run separate queries, and with the async nature of Node it's just added complexity.
Therefore I moved away from using Sequelize. Moreover I am switching from using ANY data fetching from DB in the models. In my opinion it is better to abstract getting data completely. And reasons are - imagine that you don't just use MySQL (in my case, I use MySQL and MongoDB side by side), but you can get your data from any data provider and any transport method, e.g. SQL, no-SQL, filesystem, external API, FTP, SSH etc. If you tried to do all of it in the models, you would eventually create complex and hard to understand code that would be hard to upgrade and debug.
Now what you want to do is to have models get data from a layer that knows where and how to get it, but your models only use API methods, e.g. fetch, save, delete etc. And inside this layer you have specific implementations for specific data providers. E.g. you can request certain data from a PHP file on a local machine or from Facebook API or from Amazon AWS or from remote HTML document, etc.
PS some of these ideas were borrowed from Architect by Cloud9: http://events.yandex.ru/talks/300/
I set it up as Farm and the documentation describe.
But I was having the additonal problem that in my instance methods and class methods that I would attach to the models in each function I would need to require the index file to get a hold of other database objects.
Solved it by making them accessible to all models.
var Config = require('../config/config');
var fs = require('fs');
var path = require('path');
var Sequelize = require('sequelize');
var _ = require('lodash');
var sequelize;
var db = {};
var dbName, dbUsername, dbPassword, dbPort, dbHost;
// set above vars
var sequelize = new Sequelize(dbName, dbUsername, dbPassword, {
dialect: 'postgres', protocol: 'postgres', port: dbPort, logging: false, host: dbHost,
define: {
classMethods: {
db: function () {
return db;
},
Sequelize: function () {
return Sequelize;
}
}
}
});
fs.readdirSync(__dirname).filter(function(file) {
return (file.indexOf('.') !== 0) && (file !== 'index.js');
}).forEach(function(file) {
var model = sequelize.import(path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(function(modelName) {
if ('associate' in db[modelName]) {
db[modelName].associate(db);
}
});
module.exports = _.extend({
sequelize: sequelize,
Sequelize: Sequelize
}, db);
And in the model file
var classMethods = {
createFromParams: function (userParams) {
var user = this.build(userParams);
return this.db().PromoCode.find({where: {name: user.promoCode}}).then(function (code) {
user.credits += code.credits;
return user.save();
});
}
};
module.exports = function(sequelize, DataTypes) {
return sequelize.define("User", {
userId: DataTypes.STRING,
}, { tableName: 'users',
classMethods: classMethods
});
};
I only did this for the class methods but you could also do the same thing for instance methods.
I am following the official guide: http://sequelizejs.com/heroku, which has a models folder, set up each module in separate files, and have a index file to import them and set the relationship among them.
Sample model sequelize
'use strict';
const getRole = require('../helpers/getRole')
const library = require('../helpers/library')
const Op = require('sequelize').Op
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define('User', {
AdminId: DataTypes.INTEGER,
name: {
type: DataTypes.STRING,
validate: {
notEmpty: {
args: true,
msg: 'Name must be filled !!'
},
}
},
email: {
type: DataTypes.STRING,
validate: {
notEmpty: {
args: true,
msg: 'Email must be filled !!'
},
isUnique: function(value, next) {
User.findAll({
where:{
email: value,
id: { [Op.ne]: this.id, }
}
})
.then(function(user) {
if (user.length == 0) {
next()
} else {
next('Email already used !!')
}
})
.catch(function(err) {
next(err)
})
}
}
},
password: {
type: DataTypes.STRING,
validate: {
notEmpty: {
args: true,
msg: 'Password must be filled !!'
},
len: {
args: [6, 255],
msg: 'Password at least 6 characters !!'
}
}
},
role: {
type: DataTypes.INTEGER,
validate: {
customValidation: function(value, next) {
if (value == '') {
next('Please choose a role !!')
} else {
next()
}
}
}
},
gender: {
type: DataTypes.INTEGER,
validate: {
notEmpty: {
args: true,
msg: 'Gender must be filled !!'
},
}
},
handphone: {
type: DataTypes.STRING,
validate: {
notEmpty: {
args: true,
msg: 'Mobile no. must be filled !!'
},
}
},
address: DataTypes.TEXT,
photo: DataTypes.STRING,
reset_token: DataTypes.STRING,
reset_expired: DataTypes.DATE,
status: DataTypes.INTEGER
}, {
hooks: {
beforeCreate: (user, options) => {
user.password = library.encrypt(user.password)
},
beforeUpdate: (user, options) => {
user.password = library.encrypt(user.password)
}
}
});
User.prototype.check_password = function (userPassword, callback) {
if (library.comparePassword(userPassword, this.password)) {
callback(true)
}else{
callback(false)
}
}
User.prototype.getRole = function() {
return getRole(this.role)
}
User.associate = function(models) {
User.hasMany(models.Request)
}
return User;
};
You can import models from other files with sequelize.import
http://sequelizejs.com/documentation#models-import
That way you can have one singleton module for sequelize, which then loads all the other models.
Actually this answer is quite similar to user1778770`s answer.
I am looking for an example nodejs app that uses the sequelize ORM.
You might be interested in looking at the PEAN.JS boilerplate solution.
https://github.com/StetSolutions/pean
PEAN.JS is a full-stack JavaScript open-source solution, which provides a solid starting point for PostgreSQL, Node.js, Express, and AngularJS based applications.
The PEAN project is a fork of the MEAN.JS project (not to be confused with MEAN.IO or the generic MEAN stack).
https://github.com/meanjs/mean
PEAN replaces MongoDB and the Mongoose ORM with PostgreSQL and Sequelize. A primary benefit of the MEAN.JS project is the organization it provides to a stack that has many moving pieces.
You can also use a dependency injection which provides an elegant solution to this. Here's one https://github.com/justmoon/reduct
What worked for me is to:
Create a file for each individual model like user.model.js in folder models/user.model.js.
Create index.js in models/index.js and import every model to it.
Define association, run sync method in index.js and export all models.
Create a database.js file that holds information about Sequalize and import it and initialize it in app.js
Example of one models/user.model.js
import { DataTypes } from 'sequelize';
import { sequelize } from '../database.js';
export const User = sequelize.define("user",{
uid:{
type:DataTypes.STRING,
allowNull:false,
unique: true
},
email:{
type:DataTypes.STRING,
allowNull:true
},
firstName:{
type:DataTypes.STRING,
allowNull:true
},
lastName:{
type:DataTypes.STRING,
allowNull:true
},
companyWebsite:{
type:DataTypes.STRING,
allowNull:true
},
domain:{
type:DataTypes.STRING,
allowNull:true
},
hsPortalId:{
type:DataTypes.INTEGER,
allowNull:true
},
integrations:{
type:DataTypes.STRING
},
brandedKeywords : {
type:DataTypes.STRING
},
companyName: {
type:DataTypes.STRING
},
companyStreet:{
type:DataTypes.STRING
},
companyZip:{
type:DataTypes.STRING
},
companyCountry:{
type:DataTypes.STRING
},
vatId:{
type:DataTypes.STRING
},
brand:{
type:DataTypes.STRING
},
markets:{
type:DataTypes.JSON
},
niche : {
type:DataTypes.JSON
}
},{schema:"api"})
Example of models/index.js
import { Billing } from './billing.model.js';
import { Competitor } from './competitors.model.js';
import { DemoAccount } from './demo.model.js';
import { Notification } from './notification.model.js';
import { Product } from './products.model.js';
import { Reseller } from './resellers.model.js';
import {Reseller_User} from './reseller_user.model.js'
import { Tag } from './tags.model.js';
import {User} from './user.model.js'
Reseller.belongsToMany(User, { through: Reseller_User });
User.belongsToMany(Reseller, { through: Reseller_User });
// this will create a UserId column on your Product table
// https://www.youtube.com/watch?v=HJGWu0cZUe8 40min
User.hasMany(Product,{onDelete: 'CASCADE',})
Product.belongsTo(User)
User.hasOne(DemoAccount,{onDelete: 'CASCADE',})
DemoAccount.belongsTo(User)
User.hasMany(Billing,{onDelete: 'CASCADE',})
Billing.belongsTo(User)
User.hasMany(Tag,{onDelete: 'CASCADE',})
Tag.belongsTo(User)
User.hasMany(Competitor,{onDelete: 'CASCADE'})
Competitor.belongsTo(User)
User.hasMany(Notification,{onDelete: 'CASCADE'})
Notification.belongsTo(User)
User.sync().then(
() => console.log("Sync complete")
);
Reseller.sync().then(
() => console.log("Sync complete")
);
Reseller_User.sync().then(
() => console.log("Sync complete")
);
Product.sync().then(
() => console.log("Product Sync complete")
);
Competitor.sync().then(
() => console.log("Competitor Sync complete")
);
Notification.sync().then(
() => console.log("Competitor Sync complete")
);
Billing.sync().then(
() => console.log("Billing Sync complete")
);
Tag.sync().then(
() => console.log("Tag Sync complete")
);
DemoAccount.sync()
export { User, Reseller, Product, Competitor, Notification, DemoAccount, Billing, Tag };
// DemoAccount.sync({force:true}).then(
// () => console.log("Sync complete")
// );