Mongoose deep populate with self-referencing children - angularjs

This is working code to populate my Locations collection, which can have self-referencing child Locations. It uses mongoose-deep-populate. But I need to add another ".childLocations" to my path variable for every extra level of depth that I want to handle. Is there a better way to accomplish unknown depths of self-references?
I have this node.js code.
var path = 'childLocations.childLocations.childLocations.childLocations.childLocations.childLocations';
exports.list = function(req, res) {
Location.find().sort('-created').populate('user', 'displayName').deepPopulate(path).exec(function(err, locations) {
console.log(locations);
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(locations);
}
});
};
Here is the schema:
var LocationSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Location name',
trim: true
},
projectsExecutedHere: Boolean,
childLocations: [{
type: Schema.ObjectId,
ref: 'Location'
}],
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Location', LocationSchema);
var deepPopulate = require('mongoose-deep-populate');
LocationSchema.plugin(deepPopulate);
----------
Before trying mongoose-deep-populate, I had seen that mongoose 3.6 had support for deep population, but I could only make it go one level deep. This is what I tried:
Location.find().sort('-created').populate('user', 'displayName').populate('childLocations').exec(function (err, locations) {
Location.populate(locations, {path: 'childLocations.childLocations'},
function (err, data) {
console.log(err);
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(locations);
}
}
);
For the path I also tried 'childLocations.childLocations.childLocations' but it didn't populate it at all.

Related

mongodb sending userid's in an array as a query and return the json object of the users present in collection

I have a collection of online users here goes its model
var SessionDetailSchema = mongoose.Schema({
providerID: {
type: String
},
firstName: {
type: String
},
email: {
type: String
},
status: {
type: String
}
},{ timestamps: true });
var sessionDetail = module.exports = mongoose.model('OnlineUser', SessionDetailSchema);
I am trying to send an array of providerID's so that I wanted to check the collection which all providerId's are present and return me those providerID details.
and this is what I tried
router.post('/sessiondetails:find', function (req, res, next) {
console.log(req.body.providerID)
sessionDetail.find({ "providerID": { $in: req.body.providerID} }, function (err, users) {
if (users) {
console.log(users)
} else {
console.log("not there")
}
})
})
unfortunately, I am getting the only first providerid response for multiple times.
i am sending the array from the postman it looks like this
{
"providerID":["1090867867720278", "104761648907225164100", "114316680403119099502", "103668441331122956874"]
}
can some help me? thanks in advance.

Mongoose models' save() won't update empty array

I have an array (bookedby) in a Mongoose model defined like this:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var BarSchema = new Schema({
date: {
type: Date,
required: true
},
barid: {
type: String,
required: true
},
bookedby: {
type: [String],
required: true
},
});
module.exports = mongoose.model('Bar', BarSchema);
I update it with following function, called by a nodejs express router:
const Bars = require("../../models/bars");
const { getToday } = require('../../utils');
module.exports = function(req, res) {
const { barid } = req.body;
const { username } = req.user;
const date = getToday();
if( !barid ) return res.json({ success: false, error: 'Please specify parameter \'barid\'.'})
Bars.findOne({ barid, date }, function (err, bar) {
if (err) return next(err);
if (!bar || bar.bookedby.indexOf(username) === -1) return res.json({ error: `Bar is not booked yet.` });
// Someone booked the bar
const index = bar.bookedby.indexOf(username);
bar.bookedby.splice(index, 1);
bar.save(err => {
if (err) res.json({ error: `Error saving booking.` });
else res.json({ success: true });
});
});
};
Everything works fine, except when I remove the last item from the bookedby array. Then the save() function doesn't update the database. The last item remains there. I guess it has something to do with mongodb optimizing empty arrays, but how can I solve this?
According to the Mongoose FAQ:
http://mongoosejs.com/docs/faq.html
For version >= 3.2.0 you should use the array.set() syntax:
doc.array.set(3, 'changed');
doc.save();
If you are running a version less than 3.2.0, you must mark the array modified before saving:
doc.array[3] = 'changed';
doc.markModified('array');
doc.save();

associative array is removed in post request

I have an mongoose schema with some properties and subproperties. On the version property I want a subproperty with the Mixed type, because I will send different key/value pairs to this property. But after sending the data to node, the subproperty is empty and is not saved in MongoDB.
This is my Schema
var Product = new mongoose.Schema({
name: {
type: String
},
nameSlug: {
type: String
},
uploader: {
_id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true
}
},
uploadDate: {
type: Date,
default: Date.now,
required: true
},
dateLastModified: {
type: Date,
default: Date.now,
},
isBestseller: {
type: Boolean,
default: false,
required: true
},
isVerified: {
type: Boolean,
default: false
},
suggestedRetailPrice: {
type: Number
},
brand: {
_id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true
},
nameSlug: {
type: String,
required: true
},
images: [Image]
},
productCollection: {
type: String
},
category: {
type: String,
required: true
},
versions: [{
author: [{
name: String,
_id: false
}],
date: {
type: Date,
required: true
},
concept: {
type: Boolean,
required: true
},
modifiedProperties: [mongoose.Schema.Types.Mixed],
history: [{
status: String,
author: [{
name: String,
_id: false
}],
date: Date
}]
}]
}, {strict: false});
module.exports = mongoose.model('Product', Product);
Image an subschema which is not relevant now. On the versions property I have an modifiedProperties property which I want to fill with the changed product (name, nameslug, etc) properties on a update in my Angular application. I create that object as follows
Angular code
var modifiedProperties = [];
angular.forEach($scope.addProductForm, function(value, key) {
if(key[0] == '$') return;
if(value.$dirty){
modifiedProperties[key] = value.$$lastCommittedViewValue;
}
});
var version = {
author: {
name: $rootScope.user.firstName + ($rootScope.user.lastNamePrefix ? " " + $rootScope.user.lastNamePrefix + " " : " ") + $rootScope.user.lastName,
_id: $rootScope.user._id
},
date: new Date(),
concept: true,
modifiedProperties: modifiedProperties,
history: {
author: {
name: $rootScope.user.firstName + ($rootScope.user.lastNamePrefix ? " " + $rootScope.user.lastNamePrefix + " " : " ") + $rootScope.user.lastName,
_id: $rootScope.user._id
},
status: "Versie aangemaakt",
date: new Date()
}
}
console.log("VERSION", version);
var product = $scope.product;
product.versions.push(version);
$api.update('products/' + nameSlug, product)
.then(function(response) {
console.log("response", response);
})
.catch(function(reason) {
console.log(reason);
})
In the console I see the properties correctly filled in, but after a save operation everything but modifiedProperties is saved. I placed some logs in the update function, and what I see is that the modifiedProperties is empty in the controller. I don't know where he lose it's data.
The $api service is our wrapper for the $http function. The data is there not loose, and will we be send using the data field.
The controller
module.exports.updateProduct = function(req, res) {
console.log('[updateProduct controller]');
/* This helper function can be called from elsewhere in the updateProduct controller and processes the HTTP response (and possibly errors) */
function sendResponse(status, response, err) {
/* Log HTTP response to the console server side before actually sending it to the client. */
console.log(status + ' ' + response.message);
/* Also log stack trace on error */
if(err) {
console.log('\nError message: ' + err);
console.log(err.stack);
}
/* Send HTTP response */
res.status(status).json(response);
}
if(req.params && req.params.nameSlug && req.body) {
//Empty modifiedProperties (Array(0))
console.log("REQ", req.body");
let verifyProduct;
if(req.body.verifyProduct && req.body.verifyProduct == true) {
verifyProduct = true;
delete req.body.verifyProduct;
}
console.log("PRODUCT", req.body);
req.body.dateLastModified = Date.now();
Product.findOneAndUpdate({nameSlug:req.params.nameSlug}, req.body, function (err, product) {
/* Some error occurred while trying to update the product. */
if(err) {
sendResponse(400, {message: 'Product could not be added. '}, err);
/* The product doesn't exist */
} else if(!product) {
sendResponse(404, {message: 'Product not found. '});
/* The product exists and has been updated successfully. */
} else {
/* Check if this product is being verified by an admin or not. If so, check if the admin is the same person who initially uploaded the product. */
if(verifyProduct == true && product.uploader._id != req.user._id) {
/* If so, find that user to get their email adress. */
User.findById(product.uploader._id, function(err, user) {
/* An error occurred, so mailing the original uploader is not possible. */
if(err) {
sendResponse(200, {message: 'Product updated with errors. ', product}, err);
/* The original uploader does not exist (anymore), so sending mail is not possible. */
} else if(!user) {
sendResponse(200, {message: 'Product updated, but the uploader doesn`t seem to exist. ', product});
/* Send an email to the original uploader to notify them. */
} else {
var data = {
product: product,
user: user
};
var options = {
to: user.email,
subject: product.en.name + ' is toegevoegd aan PrismaNote!',
template: 'retailer-product-verified'
};
mailService.mail(options, data, null);
sendResponse(200, {message: 'Product updated. ', product});
}
});
} else {
sendResponse(200, {message: 'Product updated. ', product});
}
}
});
}
};
Does anybody know where this can go wrong? Or why this is happen?
Edit:
I see the array modifiedProperties has a length of '0' because of the keys. Is that maybe the reason why nodejs won't proces it?
Hmm, I doesn't still know what is going wrong, but I have solved it, with passing the modifiedProperties directly to product and not in product.versions.
So, my req.body now looks like
name: "testproduct",
nameSlug: "testproduct",
isBestseller: false,
[other properties]
modifiedProperties: {
testfield: "testvalue",
field2: "value2"
},
versions: {
[
date: [today],
concept: true,
[other properties]
],
[
date: [today],
concept: true,
[other properties]
],
}

How to access, delete and edit contents in an Array using MongoDB and Express

I would really like some help with this problem, I am sorta stuck. I am trying to manipulate this UserSchema. I want to be able to edit and delete the shippings array within the model but I am having trouble trying to figure out how to access individual items in the array to use an express restAPI. Below is a snippet of the schema and the restAPI endpoint for creating multiple shipping addresses I was able to write. The create endpoint is working but for some reason I am unable to wrap my head around updating and deleting. Any help would be appreciated.
Thanks
var UserSchema = new Schema({
firstname: {
type: String,
default: ''
},
lastname: {
type: String,
default: ''
},
email: {
type: String,
unique: true,
lowercase: true,
},
password: {
type: String,
},
shippings: [{
recipient: {
type: String,
default: ''
},
street: {
type: String,
default: ''
},
city: {
type: String,
default: ''
},
state: {
type: String,
default: ''
},
zip: {
type: String,
default: ''
}
}],
exports.postShipping = function(req, res, next) {
req.assert('recipient', 'Recipient cannot be blank').notEmpty();
req.assert('street', 'Street Address cannot be blank').notEmpty();
req.assert('city', 'City cannot be blank').notEmpty();
req.assert('state', 'State cannot be blank').notEmpty();
req.assert('zip', 'Zip Code cannot be blank').notEmpty();
// req.assert('country', 'Country cannot be blank').notEmpty();
User.findById(req.user.id, function(err, user) {
if (err) return next(err);
var shipping = {};
shipping.street = req.body.street;
shipping.recipient = req.body.recipient;
// shipping.unit = req.body.unit;
shipping.city = req.body.city;
shipping.state = req.body.state;
shipping.zip = req.body.zip;
// shipping.country = req.body.country;
var s = JSON.stringify(shipping);
console.log(s);
var duplicatedShipping = 0;
for (var i in user.shippings) {
console.log(JSON.stringify(user.shippings[i]));
if (JSON.stringify(user.shippings[i]) == s) {
duplicatedShipping = 1;
break;
}
}
if (duplicatedShipping === 0) {
user.shippings.push(shipping);
}
user.save(function(err) {
if (err) return next(err);
console.log(user.shippings);
req.flash('success', {
msg: 'Shipping Address Added'
});
res.redirect('/account/me/shipping');
});
});

Get values from one collection that are used in other (MongoDB)

I'm trying to create a small prediction game for football world cup with MEAN stack, but I have a problem that I need to get all the predicted games of user and all that are not predicted yet separately.
My schemas are (users schema is the default mean-stack):
/**
* Prediction Schema
*/
var PredictionSchema = new Schema({
game_id: {
type: Schema.ObjectId,
ref: 'Game'
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
date: {
type: Date,
default: Date.now
},
choice: {
type: Number
}
});
And game schema:
var GameSchema = new Schema({
team1_key: {
type: String
},
team1_title: {
type: String
},
team2_key: {
type: String
},
team2_title: {
type: String
},
play_at: {
type: Date
},
score1: {
type: Number
},
score2: {
type: Number
}
});
mongoose.model('Game', GameSchema);
Anyway, what I'm trying to achieve is to get all games that are mentioned in all predictions and with the active user.
I tried like this, but it does not work:
/**
* List of Games predicted
*/
exports.allPredicted = function(req, res) {
Game.find({_id: {$in: Prediction.distinct('game_id')}}).sort('-created').populate('user', 'name username').exec(function(err, games) {
if (err) {
res.render('error', {
status: 500
});
} else {
res.jsonp(games);
}
});
};
What's wrong? I got error:
Error: Failed to lookup view "error" in views directory "/Users/username/Projects/ProjectName/server/views"
Any ideas? Thanks! :)
EDIT:
Got distinct values, not sure if this the create way of doing it, but anyway works.. almost:
exports.allPredicted = function(req, res) {
Prediction.distinct('game_id').populate('user', 'name username').exec(function(err, predictions) {
if (err) {
res.render('error', {
status: 500
});
} else {
console.log(predictions);
Game.find({_id: {$in: predictions }}).sort('-created').populate('user', 'name username').exec(function(err, games) {
if (err) {
res.render('error', {
status: 500
});
} else {
res.jsonp(games);
}
});
}
});
};
Now I need, that it should consider the active user as well. Any help?
you can find your active user in
req.user
so try
Prediction.find({user : req.user._id}).sort('-created').populate('game_id').exec(function(err, predictions) {
if (err) {
res.render('error', {
status: 500
});
} else {
res.jsonp(predictions);
}
});
This should return all the predictions made by your user and replace the game_id by the game associated.
ps: I don't test it but i think this is the logic of request you're looking for.
ps2 : see http://mongoosejs.com/docs/populate.html if you want to populate your users data too

Resources