Compound JS Relationship Access - node.js

I have defined 2 schema objects as below (for use in a mongodb)
var User = describe('User', function () {
property('name', String);
property('email', String);
property('password', String);
set('restPath', pathTo.users);
});
var Message = describe('Message', function () {
property('userId', String, { index : true });
property('content', String);
property('timesent', Date, { default : Date });
property('channelid', String);
set('restPath', pathTo.messages);
});
Message.belongsTo(User, {as: 'author', foreignKey: 'userId'});
User.hasMany(Message, {as: 'messages', foreignKey: 'userId'});
But I am unable to access the related messages object:
action(function show() {
this.title = 'User show';
var that = this;
this.user.messages.build({content:"bob"}).save(function(){
that.user.messages(function(err,message){
console.log('Messages:');
console.log(message);
});
});
// ... snip ...
}
});
Despite a new message being added to the message collection the array of messages is always empty.
I ran db.Message.find({userId:'517240bedd994bef27000001'}) through the mongo shell and that displayed the messages as you would expect, so I am begining to wonder if there is an issue with the mongo adapter.
One to Many relationship in CompoundJS Shows a similar issue (I think).
As far as I can work out from the docs, this should work. What am I doing wrong?
EDIT:
After applying the changes to my schema as suggested by Anatoliy I dropped my mongo database and updated npm but then when I tried to create a new user I got the below:
Express
500 TypeError: Object #<Object> has no method 'trigger' in users controller during "create" action
at Object.AbstractClass._initProperties (/mnt/share/chatApp2/node_modules/jugglingdb/lib/model.js:123:10)
at Object.AbstractClass (/mnt/share/chatApp2/node_modules/jugglingdb/lib/model.js:31:10)
at Object.ModelConstructor (/mnt/share/chatApp2/node_modules/jugglingdb/lib/schema.js:193:23)
at Function.AbstractClass.create (/mnt/share/chatApp2/node_modules/jugglingdb/lib/model.js:222:15)
at Object.create (eval at (/mnt/share/chatApp2/node_modules/compound/node_modules/kontroller/lib/base.js:157:17), :16:10)....
EDIT2:
Create action:
action(function create() {
User.create(req.body.User, function (err, user) {
respondTo(function (format) {
format.json(function () {
if (err) {
send({code: 500, error: user && user.errors || err});
} else {
send({code: 200, data: user.toObject()});
}
});
format.html(function () {
if (err) {
flash('error', 'User can not be created');
render('new', {
user: user,
title: 'New user'
});
} else {
flash('info', 'User created');
redirect(path_to.users);
}
});
});
});
});

It's an issue with ObjectID. In your schema code:
property('userId', String, { index : true });
So userId is string, but when you call user.messages user.id used (and it's an ObjectID).
As a solution just remove this line from your schema definition.
P.S. in your case you can define relations as:
Message.belongsTo('author', {model: User, foreignKey: 'userId'});
User.hasMany('messages');

Related

How to access mongoose data : Nodejs

I am getting data like this:
This is the code :
User.find({ Username: user }, function(err, found_user) {
console.log('user data'+ found_user );
if(found_user.length > 0){
console.log('inside found user');
var recordings = found_user.recordings;
console.log(recordings)
for (var singleRecords in recordings){
console.log("Single record :"+singleRecords);
if(!singleRecords.isPlayed){
console.log(singleRecords.playingUrl);
twiml.play(singleRecords.playingUrl);
found_user.recordings[singleRecords].isPlayed = true;
found_user.save(function (err) {
if(err)
throw err
});
}
}
}
And this is the value of found User :
user data { Username: 'B',
__v: 2,
_id: 58ac15e4b4e1232f6f118ba3,
recordings:
[ { isPlayed: false,
playingUrl: 'http://localhost:8000/public/toplay/playing_file_1487672817599.mp3' },
{ isPlayed: false,
playingUrl: 'http://localhost:8000/public/toplay/playing_file_1487672827411.mp3' } ]
}
inside found user
in variable found_user. But it is not giving me any data inside it. Like found_user.Username gives undefined value.
I want to store that recordings array inside a variable. Any idea how to do it ?
find() returns an array of docs that match the criteria in the callback hence the line
var recordings = found_user.recordings;
will not work as it's expecting a Document not an array.
You could use findOne() method which returns a document as:
User.findOne({ Username: user }.exec(function(err, found_user) {
console.log('user data'+ found_user );
if (found_user) {
console.log('inside found user');
var recordings = found_user.recordings;
console.log(recordings);
}
});

Mongoose.js: isModified flag for attribute with default value

I have a model with a default generated value that doesn't change throughout the document lifetime except in one special case.
A document may get marked as deleted using doc.update({_id: doc._id, deleted_at: new Date()}, {overwrite: true})
In a very special case the document may be "revived" - looked up by it's id and being worked with again afterwards.
In a pre-save hook I need to perform some action (for example store a document in another collection) whenever the document is created or revived.
Consider following simplified code:
'use strict';
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var someSchema = mongoose.Schema({
immutable: {
type: String,
default: function () {
return 'SomeVeryRandomValue';
}
}
});
someSchema.pre('save', function (next) {
if (this.isNew || this.isModified('immutable')) {
console.log('Processing pre-save hook!');
}
next();
});
var SomeModel = mongoose.model('SomeModel', someSchema, 'test');
mongoose.connection.once('open', function (err) {
var testDoc = new SomeModel({});
console.log('New: %j', testDoc.toObject());
testDoc.save(function(err) {
console.log('Initial saved: %j', testDoc.toObject());
testDoc.update({_id: testDoc._id}, {overwrite: true}, function (err) {
// at this point using mongo console:
// > db.test.findOne()
// { "_id" : ObjectId("5617b028bf84f0a93687cf67") }
SomeModel.findById(testDoc.id, function(err, reloadedDoc) {
console.log('Reloaded: %j', reloadedDoc.toObject());
console.log('reloaded isModified(\'immutable\'): %j', reloadedDoc.isModified('immutable'));
reloadedDoc.save(function(err) {
console.log('Re-saved: %j', reloadedDoc);
mongoose.connection.close();
});
});
});
});
});
And the script runtime output:
$ node mongoose-modified-test.js
New: {"_id":"5617b64c5376737b46f6bb98","immutable":"SomeVeryRandomValue"}
Processing pre-save hook!
Initial saved: {"__v":0,"_id":"5617b64c5376737b46f6bb98","immutable":"SomeVeryRandomValue"}
Reloaded: {"_id":"5617b64c5376737b46f6bb98","immutable":"SomeVeryRandomValue"}
reloaded isModified('immutable'): false
Re-saved: {"_id":"5617b64c5376737b46f6bb98","immutable":"SomeVeryRandomValue"}
The immutable is not marked as modified and IMHO it should - original document had no value for that attribute.
A work-around solution is to remove the default value for immutable attribute and define pre-validate hook like this one:
someSchema.pre('validate', function (next) {
if (this.isNew || !this.immutable) {
this.immutable = 'SomeVeryRandomValue';
}
next();
});
This is not exactly what I need because the value won't be generated until I try to validate/save the document. The pre/post-init hooks are not executed on new SomeModel({}) so I can't use those.
Should I open an issue for mongoose.js?
this.$isDefault('immutable') can be used instead.
someSchema.pre('save', function (next) {
if (this.isNew || this.$isDefault('immutable')) {
console.log('Processing pre-save hook!');
}
next();
});
Output of the script with updated pre-save hook:
$ node --harmony mongoose-modified-test.js
New: {"_id":"56276f0c1a2f17ae7e0a03f7","immutable":"SomeVeryRandomValue"}
Processing pre-save hook!
Initial saved: {"__v":0,"_id":"56276f0c1a2f17ae7e0a03f7","immutable":"SomeVeryRandomValue"}
Reloaded: {"_id":"56276f0c1a2f17ae7e0a03f7","immutable":"SomeVeryRandomValue"}
Processing pre-save hook!
Re-saved: {"_id":"56276f0c1a2f17ae7e0a03f7","immutable":"SomeVeryRandomValue"}
Thanks to #vkarpov15 for clarification.

Why is my Model.find returning nothing?

I'm very new to node and sequelize and I'm trying to follow this short introduction.
I've worked through the parts to connect to my database (postgres). I've also defined a model:
var User = sequelize.define('User', {
username: Sequelize.STRING,
password: Sequelize.STRING
});
I have succesfully synchronized the scheme and created instances. But when I attempt to read from the database using this:
User
.find({ where: { username: 'john-doe' } })
.then(function(err, johnDoe) {
if (!johnDoe) {
console.log('No user with the username "john-doe" has been found.');
} else {
console.log('Hello ' + johnDoe.username + '!');
console.log('All attributes of john:', johnDoe.get());
}
});
That instance does exist, but I only ever see the 'No user with...' message. The query it generates seems correct and when I try it manually, the returned results are what I would expect to see.
Using the same query I can do this, which also works:
sequelize.query("SELECT * FROM my_user_table where username='john-doe'", { type: sequelize.QueryTypes.SELECT})
.then(function(items) {
// We don't need spread here, since only the results will be returned for select queries
console.log(items);
});
What am I missing here?
You're mixing up promises and node-style callbacks. Typically you only expect (err, results) when you pass a callback to the original function. If you call then, you are working with promises and should only expect results. You should call catch to get any errors.
User
.find({ where: { username: 'john-doe' } })
.then(function(johnDoe) {
if (!johnDoe) {
console.log('No user with the username "john-doe" has been found.');
} else {
console.log('Hello ' + johnDoe.username + '!');
console.log('All attributes of john:', johnDoe.get());
}
})
.catch(function(err) {
// Error handling here
});
Actually, you was too close. But you must not use an argument for error handling on then method.
So you must use like the following;
User
.findOne({ where: { username: 'john-doe' } })
.then(function(johnDoe) {
if (!johnDoe) {
console.log('No user with the username "john-doe" has been found.');
} else {
console.log('Hello ' + johnDoe.username + '!');
console.log('All attributes of john:', johnDoe.get());
}
});

sails js save many to many is only one way

i have two models:
user.js
module.exports = {
attributes: {
...
profile: {
model: 'Profile'
},
groups: {
collection: 'group',
via: 'users',
dominate: true
},
roles: {
collection: 'role',
via: 'users',
dominate: true
}
}};
and, group.js
module.exports = {
attributes: {
...
users: {
collection: 'user',
via: 'groups'
}
}};
when i try to add users to a group (when i select a group and add users to it), it works as it is supposed to,
var defer = q.defer();
baseDbContext.single(req, 'users')
.then(function(op){
if(!op.status || !op.obj) {
defer.resolve(notFound);
return;
}
op.obj.users = [];
_.each(req.users, function(item){
op.obj.users.add(item);
});
op.obj.save(function(err, obj){
if(err) defer.reject(operationResult().throwException(err));
else defer.resolve(operationResult().succeed());
});
});
return defer.promise;
but when i try to add groups to the user (when i select the user and add groups to it) it fails silently!!!
var defer = q.defer();
baseDbContext.single(req, 'groups')
.then(function(op){
if(!op.status || !op.obj) {
defer.resolve(notFound);
return;
}
op.obj.groups = [];
_.each(req.groups, function(item){
op.obj.groups.add(item);
});
op.obj.save(function(err, obj){
if(err) defer.reject(operationResult().throwException(err));
else defer.resolve(operationResult().succeed());
});
});
return defer.promise;
when i check it in sails console it shows :
throw new Error('Unknown rule: ' + ruleName);
Error: Unknown rule: dominate
this is a simple many to many insertion why would it fail?
(a note about code, the function baseDbContext.single finds a object based on its id and the second parameter is for populate)
Seems like you have a misprint, documentation says that the rule you need is writes as "dominant: true", not "dominate: true".

Fetching from Model has not supply the defaults

In my app, I am fetching the data from /home -by home Model. the Model contains the defaults object. But while i fetch the data, I am not able to see the default object in the model.
here is my model :
define(['backbone'], function(Backbone){
"use strict";
socialApp = window.socialApp || {};
socialApp.homeModel = Backbone.Model.extend({
url: "/home",
defaults:{
"category":"Level-1"
}
});
return socialApp.homeModel;
});
here is my view.js :
socialApp.homeView = Backbone.Marionette.ItemView.extend({
tagName:'div',
initialize:function () {
var that = this;
this.model.fetch().done(function(data){
that.render(data) // i am fetching here
});
},
render: function (data) {
console.log(data) //there is no defaults object here...
this.$el.html(homeTemp(data));
}
});
What is wrong here? I am using Nodejs as a server.
here is the console what i am getting:
{
__v: 0
_id: "5416ce23fc0c41ec0f03f672"
email: "afzil#gmail.com"
firstName: "Mohamed"
lastName: "Afzil"
password: "afzil"
username: "afzil"
}
thanks in adavnce.
As i can see in promise 'done' callback you have only fetch results, not model.
please modify your initialize function to this:
initialize: function () {
var that = this;
this.model.fetch({
success: function(model){
that.render(model.toJSON());
}
});
}

Resources