Unhandled rejection RangeError: Maximum call stack size exceeded - bookshelf.js

I am getting this error and do not know why. Any ideas? I was sure I has this working. I am trying to pull in two identical relation types where a record has one format and one collection but the collection/format has many records.
Error
[nodemon] starting `node ./bin/www
Unhandled rejection RangeError: Maximum call stack size exceeded
at /home/ubuntu/workspace/node_modules/bookshelf/node_modules/lodash/index.js:2451:22
at isArrayLike (/home/ubuntu/workspace/node_modules/bookshelf/node_modules/lodash/index.js:4075:40)
at keys (/home/ubuntu/workspace/node_modules/bookshelf/node_modules/lodash/index.js:9674:43)
at baseAssign (/home/ubuntu/workspace/node_modules/bookshelf/node_modules/lodash/index.js:1591:28)
at /home/ubuntu/workspace/node_modules/bookshelf/node_modules/lodash/index.js:9209:11
at Function.<anonymous> (/home/ubuntu/workspace/node_modules/bookshelf/node_modules/lodash/index.js:3024:13)
at Function.<anonymous> (/home/ubuntu/workspace/node_modules/bookshelf/node_modules/lodash/index.js:8152:31)
at RelationBase (/home/ubuntu/workspace/node_modules/bookshelf/lib/base/relation.js:20:5)
at child [as constructor] (/home/ubuntu/workspace/node_modules/bookshelf/lib/extend.js:15:14)
at new child (/home/ubuntu/workspace/node_modules/bookshelf/lib/extend.js:15:14)
at _relation (/home/ubuntu/workspace/node_modules/bookshelf/lib/bookshelf.js:66:14)
at belongsTo (/home/ubuntu/workspace/node_modules/bookshelf/lib/model.js:211:17)
at bookshelf.Model.extend.format (/home/ubuntu/workspace/models/index.js:19:21)
at init (/home/ubuntu/workspace/node_modules/bookshelf/lib/relation.js:29:31)
at belongsTo (/home/ubuntu/workspace/node_modules/bookshelf/lib/model.js:211:76)
at bookshelf.Model.extend.format (/home/ubuntu/workspace/models/index.js:19:21)
at init (/home/ubuntu/workspace/node_modules/bookshelf/lib/relation.js:29:31)
at belongsTo (/home/ubuntu/workspace/node_modules/bookshelf/lib/model.js:211:76)
at bookshelf.Model.extend.format (/home/ubuntu/workspace/models/index.js:19:21)
at init (/home/ubuntu/workspace/node_modules/bookshelf/lib/relation.js:29:31)
at belongsTo (/home/ubuntu/workspace/node_modules/bookshelf/lib/model.js:211:76)
at bookshelf.Model.extend.format (/home/ubuntu/workspace/models/index.js:19:21)
at init (/home/ubuntu/workspace/node_modules/bookshelf/lib/relation.js:29:31)
at belongsTo (/home/ubuntu/workspace/node_modules/bookshelf/lib/model.js:211:76)
at bookshelf.Model.extend.format (/home/ubuntu/workspace/models/index.js:19:21)
at init (/home/ubuntu/workspace/node_modules/bookshelf/lib/relation.js:29:31)
at belongsTo (/home/ubuntu/workspace/node_modules/bookshelf/lib/model.js:211:76)
at bookshelf.Model.extend.format (/home/ubuntu/workspace/models/index.js:19:21)
`
Model
var Collection = bookshelf.Model.extend({
tableName: 'collections',
records: function() {
return this.hasMany(Record);
}
});
exports.Collection = Collection;
var Record = bookshelf.Model.extend({
tableName: 'records',
collection: function() {
return this.belongsTo(Collection);
},
format: function(){
return this.belongsTo(Format)
},
virtuals: {
largeURL: function() {
return "https://s3-eu-west-1.amazonaws.com/dartmoorweb/da" + this.get('id') + "_l.jpg";
},
mediumURL: function() {
return "https://s3-eu-west-1.amazonaws.com/dartmoorweb/da" + this.get('id') + "_m.jpg";
},
smallURL: function() {
return "https://s3-eu-west-1.amazonaws.com/dartmoorweb/da" + this.get('id') + "_s.jpg";
},
thumbURL: function() {
return "https://s3-eu-west-1.amazonaws.com/dartmoorweb/da" + this.get('id') + "_t.jpg";
}
}
});
exports.Record = Record;
var Format = bookshelf.Model.extend({
tableName: 'formats',
records: function() {
return this.hasMany(Record);
}
});
exports.Format = Format;
Route
router.get('/:id', function(req, res) {
models.Record.where('id', req.params.id).fetch({
withRelated: ['collection','format']
}).then(function(data) {
console.log(data.toJSON({virtuals: true}))
res.render('record/view.html', {
title: data.name,
data: data.toJSON({virtuals: true})
});
});
});

format: function(){
return this.belongsTo(Format)
},
format() is a method which is already defined in the modelBase of bookshelf and you are trying to override this method for a completely different purpose and therefor you've an infinite recursion.
Try to rename your format method and modify all your relations

Related

Mongoose Schema Custom Async Validator throwing TypeError - callback is not a function error

Trying to make a custom async schema validator in mongoose, to check that "tags" for a course being created contains at least one item. (Using SetTimeout() to simulate async). The part of the Schema for tags is :
tags: {
type: Array,
validate: {
isAsync: true,
validator: function (v, cb) {
setTimeout(() => {
//do some async work
const result = v && v.length > 0;
cb(result);
}, 3000);
},
message: "A course should have at least one tag!",
},
},
The code for creating a course is:
async function createCourse() {
const course = new Course({
name: "Node.js Course",
author: "Anon",
category: "web",
tags: [],
isPublished: true,
price: 13,
});
try {
const result = await course.save();
cl("createCourse result", result);
} catch (ex) {
cl("createCourse validate error", ex.message);
}
}
createCourse();
I have an empty array for tags and expected the caught error "A course should have at least one tag". Instead I am getting TypeError: cb is not a function for cb(result), the callback result? Even if I have an item in the tags array it still gives the callback error and in fact it displays the createCourse result BEFORE the schema async completes and then throws the error when it does complete! (If I dont use the async validator but just a plain validator then it works fine).
tags: {
type: Array,
validate: {
validator: function(v) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(v && v.length > 0);
}, 3000);
})
},
message: 'A course should have at least one tag.'
}
},
After trial and error, I came up with the solution below. No changes needed to createCourse(), just to the Schema tags section and added a delay function.
tags: {
type: Array,
validate: {
//isAsync: true,
validator: async function (v) {
await delay(3);
const result = v && v.length > 0;
return result;
},
message: "A Document should have at least one tag!",
},
},
And this calls a delay function, used to simulate a "real" async situation where this data may be being saved to a remote server.
const delay = (n) => {
return new Promise(function (resolve) {
setTimeout(resolve, n * 1000);
});
};

Meteor observe not working properly in 1.6

I recently upgraded from 1.2 to Meteors latest version 1.6.0.1.
I was using observe in a publication and an observe on the client to get changes.
in 1.2 no problems at all, but in 1.6 observed changes are not received in a "changed" client callback, but the client does get the ddp message. I can verify that by looking in Chromes dev tools > websocket, see the incoming message, but it's never fired in a client callback. This only happens when changing 2-3 documents at a time.
So when I delete a few documents from the DB, the publication fires off the callbacks, and the client receives them in the websocket messages, but it only fires once in the "observe" callback on the client.
Here is my code.
Client -
CollectionTest = new Meteor.Collection('collectionTest');
CollectionTest.find({}).observe({
added: function (doc) {
console.log("ADDED DOC ", doc);
},
changed: function (newDoc, oldDoc) {
console.log("CHANGED DOC new ", newDoc);
},
removed: function (doc) {
console.log("REMOVED DOC ", doc);
}
});
Server Publication -
Meteor.publish("ddpPub", function () {
var self = this,
ready = false;
var userId = self.userId;
var subHandle = TestData.find({}).observeChanges({
added: function (id, fields) {
if (ready) {
self.changed("collectionTest", userId, {
type: "added",
data: {
id: id,
fields: fields
}
});
}
},
changed: function (id, fields) {
if (ready) {
self.changed("collectionTest", userId, {
type: "changed",
data: {
id: id,
fields: fields
}
});
}
},
removed: function (id) {
if (ready) {
self.changed("collectionTest", userId, {
type: "removed",
data: id
});
}
}
});
self.added("collectionTest", userId);
self.ready();
ready = true;
self.onStop(function () {
subHandle.stop();
});
});
Attached are images from me removing the documents from the DB. The websocket messages, and then my console on the client. Showing it only fires once for 5 documents.
Showing the document id's I am deleting
DDP messages in 'websocket' confirmed they get to client
Single client message in client callback showing only document changed
UPDATE: 12/15/17 - 7:17pm PST
After working on this for a couple hours, finding some related meteor posts with observe callbacks and “Meteor.call” not working inside, the solution or hack is to wrap the “Meteor.call” in a “setTimeout” with the value of 0, and it fixes it.
I tried that here, and it didn’t work, but then I tried throttle the response, and it works! Not sure if it's a reliable fix, but it's the only one I found so far.
I am not sure why this works, or what causes the problem in the first place, any explanation would be welcome.
Server Publication -
Meteor.publish("ddpPub", function () {
var self = this,
ready = false;
var userId = self.userId;
var subHandle = TestData.find({}).observeChanges({
added: function (id, fields) {
if (ready) {
console.log("ADDING PUBLICATION");
self.changed("collectionTest", userId, {
type: "added",
data: {
id: id,
fields: fields
}
});
}
},
changed: function (id, fields) {
if (ready) {
console.log("CHANGING PUBLICATION");
self.changed("collectionTest", userId, {
type: "changed",
data: {
id: id,
fields: fields
}
});
}
},
removed: function (id) {
if (ready) {
console.log("REMOVING PUBLICATION");
ratePub(id, function (data) {
console.log("OBJECT DATA IS ", data);
self.changed("collectionTest", userId, data);
});
}
}
});
self.added("collectionTest", userId);
self.ready();
ready = true;
self.onStop(function () {
subHandle.stop();
});
});
var returnPub = function (id, callback) {
console.log("RETURNING PUB ");
callback({
id: id,
type: "removed",
data: id
});
};
var ratePub = _.rateLimit(returnPub, 10);

How do I write an item to a DynamoDb with the AWS DynamoDB DocumentClient?

I'm having trouble with the AWS DynamoDb JS SDK v2.4.9. I want to use the DocumentClient class as opposed to the lower level DynamoDb class, but can't get it working.
This works:
function testPutItem( callback ) {
var tableName = 'todos';
var params = {
TableName: tableName,
Item: {
user_id: { S : userId },
id: { N : msFromEpoch }, // ms from epoch
title: { S : makeRandomStringWithLength(16) },
completed: { BOOL: false }
}
};
var dynamodb = new AWS.DynamoDB();
dynamodb.putItem(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else {
console.log(data); // successful response
if (callback) callback(data);
}
});
}
This does not work and gives the error InvalidParameterType: Expected params.Item[attribute] to be a structure for each attribute--as if DocumentClient is expecting the same input as DynamoDb:
function testPutItem( callback ) {
var tableName = 'todos';
var params = {
TableName: tableName,
Item: {
user_id: userId,
id: msFromEpoch,
title: makeRandomStringWithLength(16),
completed: false
}
};
console.log(params);
var docClient = new AWS.DynamoDB.DocumentClient({region: 'us-east-1'});
docClient.put(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else {
console.log(data); // successful response
if (callback) callback(data);
}
});
}
Does anyone have any idea what I am doing wrong?
I used to have the same issue,
please try with a simple object first, cause it's due to some special characters in your attributes, see my example :
this generates the error
InvalidParameterType: Expected params.Item[attribute] to be a structure
var Item = {
domain: "knewtone.com",
categorie: "<some HTML Object stuff>",
title: "<some HTML stuff>",
html: "<some HTML stuff>""
};
but when i replace the HTML stuff with a formated Html, simple characters , it works
var Item = {
domain: "knewtone.com",
categorie: $(categorie).html(),
title: $(title).html(),
html: $(html).html()
};

how to waitOn data ready using iron-router and publish-composite

I have the following route :
this.route('groupPage', {
path: '/group/:_groupId',
waitOn: function(){
return Meteor.subscribe("groupPage", this.params._groupId);
},
data: function() {
var group = Groups.findOne({_id: this.params._groupId});
var members = Meteor.users.find({_id : {$in: group.memberIds}}); ******** ISSUE HERE******
return {
group: group,
members: members,
}; }});
and the following publication :
Meteor.publishComposite('groupPage', function(groupId, sortOrder, limit) {
return {
// return the group
find: function() {
if(this.userId){
var selector = {_id: groupId};
var options = {limit: 1};
return Groups.find(selector, options);
}
else{
return ;
}
},
children: [
{ // return the members
find: function(group) {
var selector = {_id: {$in: group.memberIds} };
return Meteor.users.find(selector);
}
}
]}}) ;
Now my issue is that : when the related page renders for the first there is no problems but when i actualize the group Page view the line : var members = Meteor.users.find({_id : {$in: group.memberIds}}); gives me the error : undefined object don't have memberIds property. i guess it's because the subscription is not yet ready when doing group.memberIds , isn't it ? Please a hint.
Thanks.
The data function doesn't wait for the subscription to be ready. Further more, subscriptions in the router are considered an anti-pattern for the most part, and should be done in the template: https://www.discovermeteor.com/blog/template-level-subscriptions/
I would pass to the template the groupId, and then get the group and members in the template, like so:
this.route('groupPage', {
path: '/group/:_groupId',
data: function() {
return {
_groupId: this.params._groupId,
}
}
});
and then in the template file:
Template.groupPage.onCreated(function(){
this.subscribe("groupPage", this.data._groupId);
})
Template.groupPage.helpers({
members(function(){
tempInst = Template.instance()
var group = Groups.findOne({_id: tempInst.data._groupId});
return Meteor.users.find({_id : {$in: group.memberIds}});
})
})
The general pattern of your route and publication are all solid. I suspect it's something simple such as:
There is no group with the _id you're using
You're not logged in when you load the route
Here's a version of your code that guards against the error. Note that the publication executes this.ready() instead of just returning if the user is not logged in.
this.route('groupPage', {
path: '/group/:_groupId',
waitOn: function(){
return Meteor.subscribe("groupPage", this.params._groupId);
},
data: function() {
var group = Groups.findOne({_id: this.params._groupId});
var members = group && Meteor.users.find({_id : {$in: group.memberIds}});
return { group: group, members: members };
}
});
Meteor.publishComposite('groupPage', function(groupId,sortOrder,limit) {
return {
find: function() {
if (this.userId) return Groups.find(groupId);
this.ready()
}
},
children: [
find: function(group) {
var selector = {_id: {$in: group.memberIds} };
return Meteor.users.find(selector);
}
]
});

Meteor cfs standard packages - check Error

While trying to upload a File to my Database, I am getting a Match Error that is preventing the File to be stored.
Here is the Basic code:
The Initialization:
UserImages = new FS.Collection("userImages", {
stores: [new FS.Store.FileSystem("userImages", {path: "~/uploads"})],
filter: {
maxSize: 1048576, //in bytes
allow: {
contentTypes: ['image/*'],
extensions: ['png', 'jpg']
},
onInvalid: function (message) {
if (Meteor.isClient) {
alert(message);
} else {
console.log(message);
}
}
}
});
if(Meteor.isServer){
UserImages.allow({
insert:function(userId, doc){
return true;
},
update:function(userId, doc, fields, modifier){
check(doc, Object);
return true;
},
remove:function(){
return true;
}
})
}
The Client Code:
Template.editProfile.events({
'change #profileUpload':function(event, template){
var files = event.target.files;
for (var i = 0, ln = files.length; i < ln; i++) {
UserImages.insert(files[i], function (err, fileObj) {
if(err){
console.log(err);
}
});
}
}
});
Strangly enough, if i run a console.log(typeof file) it gives me back an Object. But when i check the File against an Object with check(file, Object) it gives me this Error:
This is the Stack from the Server:
Exception in setTimeout callback: Error: Match error: Expected plain object
at checkSubtree (packages/check/match.js:279:1)
at check (packages/check/match.js:32:1)
at UserImages.allow.update (app/server/allowances.js:91:7)
at packages/mongo/collection.js:1041:1
at Array.every (native)
at Function._.every._.all (packages/underscore/underscore.js:219:1)
at [object Object].Mongo.Collection._validatedUpdate (packages/mongo/collection.js:1038:1)
at [object Object].m.(anonymous function) (packages/mongo/collection.js:851:1)
at Object.methods.rateLimit.callFunctionsInQueue (packages/matteodem:easy-security/lib/easy-security.js:72:1)
at packages/matteodem:easy-security/lib/easy-security.js:116:1
Has anyone encountered this problem or has a solution for a workaround? I've tried all kinds of workarounds also with Match.Any but than I get an error telling me that all Arguments have not been run against the check();
I checked the issues in here:
https://github.com/CollectionFS/Meteor-cfs-base-package/issues
https://github.com/CollectionFS/Meteor-CollectionFS/issues
but could not find a solution so far.
Thanks for the help!

Resources