I'm a bit stuck on this problem.
I have read all the mongoose documentation about middleware and some stackoverflow issue and was unable to find-out how to solve my problem without duplicating queries (find then remove).
Normally, pre middleware on remove will not fire when call from Model and not from document. But according with the doc, if I add {query: true}, my function will be called from model query.
I use the latest monngoose version (5.4.16)
Here is my code.
let mySchema= new mongoose.Schema({
name: String,
comment: String
}, { usePushEach: true });
mySchema.pre('remove', { document: true }, function() {
console.log('remove document');
});
mySchema.pre('remove', { query: true }, function() {
console.log('remove');
});
const MyModel = mongoose.model('MyModel', mySchema);
And the call here
MyModel.deleteOne({ _id: modelId }, (errorRm) => {
if (errorRm) {
return res.json({ success: false, message: `${errorRm.message}` });
}
return res.json({ success: true, message: 'Model successfully removed' });
});
The model is successfully removed but nothing is logged from the "pre" functions...
Any help would be welcomed.
It's because you're using MyModel.deleteOne(). Use MyModel.remove() and it will work.
Acoording to the documentation:
You can pass options to Schema.pre() and Schema.post() to switch whether Mongoose calls your remove() hook for Document.remove() or Model.remove():
Related
I am using updatingAll method in loopback but it is not working I am not able to understand the reason
I have written something like this
let data = {
isActive: false
};
myModel
.updateAll(data, {
id: {
inq: questionIds
},
});
The order of parameters in updateAll seems to be incorrect. From documentation:
PersistedModel.updateAll([where], data, callback)
Also, it seems a callback function is required.
Callback function called with (err, info) arguments. Required.
So your call should look like this:
let data = {
isActive: false
};
myModel.updateAll({
id: {
inq: questionIds
},
}, data, (err, info) => null); //might want to add error checking to callback function
I am using 5.3.2 in basic mode as I need control over the UI.
I have added code to allow the uploads and then created little UI elements that can then trigger a deletion. I need to know the filename when I am deleting. So I used setDeleteFileParams but nothing is attached to the request.
var uploader = new qq.FineUploaderBasic({
button: document.getElementById('btnUploadFiles'),
debug: true,
autoUpload: true,
request: {
paramsInBody: true,
endpoint: '../myendpoint.htm',
params: {
tempID: 'myidwhatever'
}
},
deleteFile: {
enabled: true,
forceConfirm: false,
method: 'POST',
endpoint: '../myendpoint.htm'
},
callbacks: {
onSubmitted: function(id, name){
//do work
},
onDelete: function(id) {
this.setDeleteFileParams({filename: this.getName(id)}, id);
},
onDeleteComplete: function(UID, xhr, isError){
//remove my UI element
},
onComplete: function(UID, name, responseJSON, xhr) {
//create an element and stick it in
}
}
})
//ADD THE DELETE BUTTON ACTIONS
$('uploadedFiles').addEvent("click:relay(.deleteMyFile)", function(event, element) {
event.preventDefault();
arr = element.id.split('_')
uploader.deleteFile(arr[1]);
});
Im using Mootools as my JS framework. Everything triggers ok and the console logs out the filename correctly when I delete a file but when I look at the request there is no 'filename' parameter.
Thanks for any help.
By the time your onDeleteFile callback has been called, the file is already setup to be deleted. If you'd like to influence (or prevent) the underlying request, you'll need to put your logic inside of a onSubmitDelete callback handler instead.
For example:
callbacks: {
onSubmitDelete: function(id) {
console.log(this.getName(id));
this.setDeleteFileParams({filename: this.getName(id)}, id);
}
}
Trying to return a list of articles specific to a sectionId in angular controller. I can get back the entire list of articles using articles.query but the passed sectionId query param gets completely ignored. I tried a to abstract it to an articles service but I'm not sure how to build services correctly yet so it threw more errors. Any help / examples of how I might achieve this, preferable as a service, would be great. I am using mean.js. Thanks in advance!
Sections controller
angular.module('sections').controller('SectionsController', ['$scope', '$stateParams', '$location', 'Authentication', 'Sections', 'SectionArticlesList', 'Articles',
function($scope, $stateParams, $location, Authentication, Sections, SectionArticlesList, Articles) {
..........
// Find existing Section
$scope.findOne = function() {
$scope.section = Sections.get({
sectionId: $stateParams.sectionId // sections return fine
});
// problem starts here
$scope.articles = Articles.query({
section:$stateParams.sectionId // this param is ignored
});
$scope.articles.$promise.then(function(data) {
// all articles in collection returned instead of section specific
console.log('Articles: '+ JSON.stringify(data));
$scope.articles = data;
});
Articles Model
var ArticleSchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true,
required: 'Title cannot be blank'
},
content: {
type: String,
default: '',
trim: true
},
section: {
type: Schema.ObjectId,
ref: 'Section'
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
UPDATE:
Following up on the advice of Kevin B and Brad Barber below, I tried adding a factory and node server route, passing the $stateParams.sectionId to the specific factory instance. I created a new route in the articles.routes.server to make sure not to have a conflict with the standard ‘/articles/:articleId’ route. Unfortunately, anything I try still either throws errors or everything in the articles collection which is the opposite of what I want to do.
section.client.controller
// Find existing Section
$scope.findOne = function() {
$scope.section = Sections.get({
sectionId: $stateParams.sectionId
});
// fails no matter what is passed to query
$scope.articles = SectionArticlesList.query($stateParams.sectionId);
//$scope.SectionArticlesList.query($stateParams.sectionId);
//$scope.articles = SectionArticlesList.query({sectionId});
$scope.articles.$promise.then(function(data) {
// still only ever returns full list of articles
console.log('Length of articles: '+ JSON.stringify(data.length));
$scope.articles = data;
});
….
articles.client.services
angular.module('articles').factory('SectionArticlesList', ['$resource',
function($resource) {
return $resource('articles/:articleSectionId', {
articleSectionId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
]);
articles.server.routes
// Custom route
app.route('/articles/:articleSectionId')
.get(articles.listBySectionID);
// Custom binding
app.param('articleSectionId', articles.listBySectionID);
articles.server.controller
The server side controller function never appears to get called because neither of the console.logs show up.
exports.listBySectionID = function(req, res, id) {
console.log('listBySection Called....'); // this is never printed
// have tried passing - id, sectionId and {section:id}
Article.find( {section:id} ).sort('-created').populate('user', 'displayName').exec(function(err, articles) {
if (err) {
console.log('listBySection err triggered...'); // this neither
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(articles);
}
});
};
I think I have tried everything I can think of to pass the sectionId correctly but nothing has worked yet. The latest error in the console is the 404 below.Interestingly the sectionId IS getting through but as if it is looking for one single resource such as a single blog post.
GET /sectionArticles?sectionId=555bfaf29a005c30cbfe6931 404
I don't quite understand how the default mean.js /articles route and it's corresponding list function works but duplicating a similar structure and passing an id as a param to the query to retrieve only specific results doesn't.
Would really like to understand how this should be wired up. If anyone can point out what I am doing wrong I’d appreciate it!
Edit 11/16/14: Version Information
DEBUG: Ember : 1.7.0 ember-1.7.0.js:14463
DEBUG: Ember Data : 1.0.0-beta.10+canary.30d6bf849b ember-1.7.0.js:14463
DEBUG: Handlebars : 1.1.2 ember-1.7.0.js:14463
DEBUG: jQuery : 1.10.2
I'm beating my head against a wall trying to do something that I think should be fairly straightforward with ember and ember-data, but I haven't had any luck so far.
Essentially, I want to use server data to populate a <select> dropdown menu. When the form is submitted, a model should be created based on the data the user chooses to select. The model is then saved with ember data and forwarded to the server with the following format:
{
"File": {
"fileName":"the_name.txt",
"filePath":"/the/path",
"typeId": 13,
"versionId": 2
}
}
The problem is, the typeId and versionId are left out when the model relationship is defined as async like so:
App.File = DS.Model.extend({
type: DS.belongsTo('type', {async: true}),
version: DS.belongsTo('version', {async: true}),
fileName: DS.attr('string'),
filePath: DS.attr('string')
});
The part that is confusing me, and probably where my mistakes lie, is the controller:
App.FilesNewController = Ember.ObjectController.extend({
needs: ['files'],
uploadError: false,
// These properties will be given by the binding in the view to the
//<select> inputs.
selectedType: null,
selectedVersion: null,
files: Ember.computed.alias('controllers.files'),
actions: {
createFile: function() {
this.createFileHelper();
}
},
createFileHelper: function() {
var selectedType = this.get('selectedType');
var selectedVersion = this.get('selectedVersion');
var file = this.store.createRecord('file', {
fileName: 'the_name.txt',
filePath: '/the/path'
});
var gotDependencies = function(values) {
//////////////////////////////////////
// This only works when async: false
file.set('type', values[0])
.set('version', values[1]);
//////////////////////////////////////
var onSuccess = function() {
this.transitionToRoute('files');
}.bind(this);
var onFail = function() {
this.set('uploadError', true);
}.bind(this);
file.save().then(onSuccess, onFail);
}.bind(this);
Ember.RSVP.all([
selectedType,
selectedVersion
]).then(gotDependencies);
}
});
When async is set to false, ember handles createRecord().save() POST requests correctly.
When async is true, ember handles GET requests perfectly with multiple requests, but does NOT add the belongsTo relationships to the file JSON during createRecord().save(). Only the basic properties are serialized:
{"File":{"fileName":"the_name.txt","filePath":"/the/path"}}
I realize this question has been asked before but I have not found a satisfactory answer thus far and I have not found anything that suits my needs. So, how do I get the belongsTo relationship to serialize properly?
Just to be sure that everything is here, I will add the custom serialization I have so far:
App.ApplicationSerializer = DS.RESTSerializer.extend({
serializeIntoHash: function(data, type, record, options) {
var root = Ember.String.capitalize(type.typeKey);
data[root] = this.serialize(record, options);
},
keyForRelationship: function(key, type){
if (type === 'belongsTo') {
key += "Id";
}
if (type === 'hasMany') {
key += "Ids";
}
return key;
}
});
App.FileSerializer = App.ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
type: { serialize: 'id' },
version: { serialize: 'id' }
}
});
And a select:
{{ view Ember.Select
contentBinding="controller.files.versions"
optionValuePath="content"
optionLabelPath="content.versionStr"
valueBinding="controller.selectedVersion"
id="selectVersion"
classNames="form-control"
prompt="-- Select Version --"}}
If necessary I will append the other routes and controllers (FilesRoute, FilesController, VersionsRoute, TypesRoute)
EDIT 11/16/14
I have a working solution (hack?) that I found based on information in two relevant threads:
1) How should async belongsTo relationships be serialized?
2) Does async belongsTo support related model assignment?
Essentially, all I had to do was move the Ember.RSVP.all() to after a get() on the properties:
createFileHelper: function() {
var selectedType = this.get('selectedType');
var selectedVersion = this.get('selectedVersion');
var file = this.store.createRecord('file', {
fileName: 'the_name.txt',
filePath: '/the/path',
type: null,
version: null
});
file.set('type', values[0])
.set('version', values[1]);
Ember.RSVP.all([
file.get('type'),
file.get('version')
]).then(function(values) {
var onSuccess = function() {
this.transitionToRoute('files');
}.bind(this);
var onFail = function() {
alert("failure");
this.set('uploadError', true);
}.bind(this);
file.save().then(onSuccess, onFail);
}.bind(this));
}
So I needed to get() the properties that were belongsTo relationships before I save the model. I don't know is whether this is a bug or not. Maybe someone with more knowledge about emberjs can help shed some light on that.
See the question for more details, but the generic answer that I worked for me when saving a model with a belongsTo relationship (and you specifically need that relationship to be serialized) is to call .get() on the properties and then save() them in then().
It boils down to this:
var file = this.store.createRecord('file', {
fileName: 'the_name.txt',
filePath: '/the/path',
type: null,
version: null
});
// belongsTo set() here
file.set('type', selectedType)
.set('version', selectedVersion);
Ember.RSVP.all([
file.get('type'),
file.get('version')
]).then(function(values) {
var onSuccess = function() {
this.transitionToRoute('files');
}.bind(this);
var onFail = function() {
alert("failure");
this.set('uploadError', true);
}.bind(this);
// Save inside then() after I call get() on promises
file.save().then(onSuccess, onFail);
}.bind(this));
I'm using Sails.js version 0.10.x, and am just starting to try out it's associactions stuff.
In my scenario I have a User who has many Documents.
so in /api/models/User.js I have:
module.exports = {
// snipped out bcrypt stuff etc
attributes: {
email: {
type: 'string',
unique: true,
index: true,
required: true
},
documents: {
collection: 'document',
via: 'owner'
},
}
};
and in /api/models/Document.js I have:
module.exports = {
attributes: {
name: 'string',
owner: {
model: 'user'
}
}
};
In my DocumentController I have the following:
fileData = {
name: file.name,
owner: req.user
}
Document.create(fileData).exec(function(err, savedFile){
if (err) {
next(err);
} else {
results.push({
id: savedFile.id,
url: '/files/' + savedFile.name,
document: savedFile
});
next();
}
});
Looking in my local mongo database via the command line I can see that the documents have the owner field set as follows "owner" : ObjectId("xxxxxxxxxxxxxxxxxxxxxxxx") which is as expected.
However when I inspect the req.user object later in the DocumentController via sails.log.debug("user has documemts", req.user.documents); I see
debug: user has documents [ add: [Function: add], remove: [Function: remove] ]
And not an array of Document objects.
In my resulting slim template
if req.user.documents.length > 0
ul
for doc in req.user.documents
li= doc.toString()
else
p No Documents!
I always get "No Documents!"
I seem to be missing something obvious but I'm not sure what that is.
I worked this out by wading through the Waterline source code.
Firstly, as I hoped, both sides of the association are affected by the creation of the Document instance, and I simply needed to reload my user.
Within the controller this is as simple as User.findOne(req.user.id).populateAll().exec(...)
I also modified my passport service helper as follows
function findById(id, fn) {
User.findOne(id).populateAll().exec(function (err, user) {
if (err) return fn(null, null);
return fn(null, user);
});
}
function findByEmail(email, fn) {
User.findOne({email: email}).populateAll().exec(function (err, user) {
if (err) return fn(null, null);
return fn(null, user);
});
}
Now the user, and its associations, are loaded properly per request.
I had to dig through the source to find the populateAll() method as it's not actually documented anywhere I could find. I could also have used populate('documents') instead but I am about to add other associations to the User so need populateAll() to load all the relevant associations.
Waterline associations docs
Waterline /lib/waterline/query/deferred.js#populateAll