Mongoose find by data field from schema into services - mongodb

If i have a schema like this in my mongoose
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var lovSchema = new mongoose.Schema({
name : { type: String },
values : [{ type: String }]
});
module.exports = mongoose.model('lovs', lovSchema);
Generally in mongoose we find document with reff to _id from collections.
function getOneById(id){
var deferred = Q.defer();
model.findOne({ _id: id })
.exec(function (err, item) {
if(err) {
console.log(err);
deferred.reject(err);
}
else
console.log(item);
deferred.resolve(item);
});
return deferred.promise;
} // gentOneById method ends
But I want to find the document by Name which is a data field in my schema.I tried by modifying _id with name but ended with this error...
{
"message": "Cast to ObjectId failed for value \"regions\" at path \"_id\"",
"name": "CastError",
"type": "ObjectId",
"value": "regions",
"path": "_id"
}

Just use name with a String value:
function getOneByName(name){
var deferred = Q.defer();
model.findOne({ name: name})
.exec(function (err, item) {
if(err) {
console.log(err);
deferred.reject(err);
}
else
console.log(item);
deferred.resolve(item);
});
return deferred.promise;
} // gentOneById method ends
You can test like this:
model.findOne({ name: "Bob"})
And see if you still get an error...

Related

Store a mongodb document inside another document

I am trying to save MongoDB document from one collection to another collection. Iw want to it look like this when retrieving via my API endpoint. I create errors separately and want to join it with machine via id.
{
"_id": "59634780c464263b28a6891a",
"name": "GLUE-SM-21",
"status": false,
"__v": 0,
"error": {
"_id" : ObjectId("59769b9ad1050f244cadfced"),
"count" : 5,
"name" : "Error-001-J",
"__v" : 0
}
}
But I am getting this.
{
"_id": "59634780c464263b28a6891a",
"name": "GLUE-SM-21",
"status": false,
"__v": 0,
"error": [
"59769b9ad1050f244cadfced"
]
}
Here I am attaching my current work.
Error Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ErrorSchema = new Schema({
name: String,
count: Number
});
module.exports = mongoose.model('Error', ErrorSchema);
Machine Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
const ObjectId = Schema.Types.ObjectId;
var Error = require('./error');
var MachineSchema = new Schema({
name: String,
status: Boolean,
error: [{ type: ObjectId, ref: 'Error', default: null }]
});
module.exports = mongoose.model('Machine', MachineSchema);
In the default case There is no error. Here is my save code.
var machine = new Machine(); // create a new instance of the Machine model
machine.name = req.body.name; // set the machine name (comes from the request)
machine.status = 1; // set the machine status (comes from the request)
machine.error = null;
machine.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Machine created!' });
});
Here is my update code.
Machine.findById(req.params.machine_id, function(err, machine) {
if (err)
res.send(err);
machine.name = machine.name;
if(req.body.error && machine.status) {
machine.status = false;
} else if(!req.body.error && !machine.status) {
machine.status = true;
}
machine.error = req.body.error;
machine.save(function(err) {
if (err)
res.send(err);
io.emit('machine', machine);
res.json({ message: 'Machine updated!' });
});
});
I have found a solution.
I have saved object ID of error document inside my Machine document as error attribute. I have updated my code using populate function on mongo.
Machine.find().populate("error").exec(
function(err, machines) {
if (err)
res.send(err);
res.json(machines);
}
);

Updated date field is not updated

I have defined this schema
var docSchema = mongoose.Schema({
name:{type:String,required:true},
}, { timestamps: { createdAt: 'createdAt',updatedAt:'updatedAt' }, collection : 'docs', discriminatorKey : '_type' });
I update the documents using this route
router.post('/:id', auth, function(req,res,next) {
var id = req.params.id;
docA.findByIdAndUpdate(id, req.body, {new: true}, function(err, doc) {
if(err)
res.json(err);
else if(doc==null)
res.status(404).send({
message: "Document not found"
});
else
res.json(doc);
});
});
I noticed updatedAt is not updated when I save some edits to the documents.
Besides this problem, thinking about it, it could be helpful to keep this data in form of array of updated date like:
updatedAt : [
"2016-10-25T12:52:44.967Z",
"2016-11-10T12:52:44.967Z",
"2016-12-01T12:52:44.967Z"
]
SOLUTION(?):According to #chridam suggestions, my current workaround to keep an array of update Dates is:
docSchema.pre(`findOneAndUpdate`, function(next) {
if(!this._update.updateHistory) {
console.log("findOneAndUpdate hook: updateHistory not present")
this._update.updateHistory=[];
}
this._update.updateHistory.push(new Date);
return next();
});
docSchema.pre('save', function (next) {
if(!this.updateHistory) {
console.log("Save hook: updateHistory not present")
this.updateHistory=[];
}
this.updateHistory.push(new Date);
next();
});
This is a known issue, please refer to the original thread on the plugin here, where dunnkers commented:
It's actually impossible to hook middleware onto update,
findByIdAndUpdate, findOneAndUpdate, findOneAndRemove and
findByIdAndRemove in Mongoose at the moment.
This means that no plugin is actually run when using any of these
functions.
Check out the notes section in the Mongoose documentation for
middleware. Issue Automattic/mongoose#964 also describes this.
As a suggested workaround, factoring in your schema changes:
var docSchema = mongoose.Schema({
"name": { "type": String, "required": true },
"updateHistory": [Date]
}, {
"timestamps": {
"createdAt": 'createdAt',
"updatedAt": 'updatedAt'
},
"collection" : 'docs',
"discriminatorKey": '_type'
});
router.post('/:id', auth, function(req,res,next) {
var id = req.params.id;
docA.findByIdAndUpdate(id, req.body, {new: true}, function(err, doc) {
if(err)
res.json(err);
else if(doc==null)
res.status(404).send({
message: "Document not found"
});
else {
doc.updateHistory.push(new Date());
doc.save().then(function(doc){
res.json(doc);
}, function(err) {
// want to handle errors here
})
}
});
});
Another approach would be to attach a hook to the schema:
docSchema.pre("findOneAndUpdate", function() {
this.updatedAt = Date.now();
});

Trouble in inserting sub-documents using mongoose

I created an Enterprise database using mongoose in node-express project.Now I need to add employee sub document in the enterprise_employee field of the enterprise database, but it throws an error.
Following code snippet is my schema
var mongoose= require('mongoose');
var Enterprise= new mongoose.Schema({
enterprise_id:{
type:String
},
enterprise_name:{
type:String
},
enterprise_email:{
type:String
},
enterprise_employee: [{employee_id:Number, employee_name:String}]
});
module.exports={
Enterprise:Enterprise
};
This code snippet is the route for adding employee sub-document
var mongoose = require('mongoose');
var Enterprise = mongoose.model('Enterprise_gpy');
var addEmployee = function(req, res){
Enterprise.findOne({"enterprise_id":req.body.enterprise_id},function(err, res){
if(err){
console.log('NO SUCH ORGANISATION');
res.json(err);
} else {
Enterprise.enterprise_employee.push({
"employee_id": req.body.employee_id,
"employee_name":req.body.employee_name
});
}
});
}
module.exports={
addEmployee:addEmployee
};
This the error thrown
throw er; // Unhandled 'error' event
^ TypeError: Cannot read property 'push' of undefined
Seems like what you need is an update operation that uses the $push operator to add the elements to the array field. The following example demonstrates this:
Enterprise.findOneAndUpdate(
{ "enterprise_id": req.body.enterprise_id },
{
"$push": {
"enterprise_employee": {
"employee_id": req.body.employee_id,
"employee_name":req.body.employee_name
}
}
},
{ "new": true }, // return the modified document
function(err, enterprise) {
if (err) {
console.log('NO SUCH ORGANISATION');
res.json(err);
} else {
console.log(enterprise); // modified document
}
}
);
I think this is because your schema needs to define the enterprise_employee as an array. You have to explicitly tell Mongoose that it should be an 'Array' type.
Try this:
enterprise_employee: {
type: Array,
fields: [
{
employee_id: String,
employee_name: String
}
]
}

MongoDB not respecting $set { name: "a value" } in update query

I'm writing my own API in express to perform mongo update queries and I'm having trouble updating the "name" field specifically.
TagHandles.update(
{"uuid":req.params.id},
// {$set: { name : "piers" } },
{$set: { type : "works" } },
{upsert:true,safe:false},
function(err, data){
if (err){
console.log("ERROR");
console.log(err);
console.log(data);
} else {
console.log("SUCCESS");
console.log(err);
console.log(data);
}
res.send(err || data);
});
The TagHandles is a mongoose model with the following Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var TagHandle = new Schema({
type: String,
uuid: String,
handle: String
}, {
collection: 'tagHandles'
});
var TagHandles = mongoose.model('tagHandles', TagHandle);
Apparently mongoose prevents you from updating any fields not listed as part of the schema. So to correct, I added the line:
name: String
to the mongoose schema.

How to update embedded document in mongoose?

I've looked through the mongoose API, and many questions on SO and on the google group, and still can't figure out updating embedded documents.
I'm trying to update this particular userListings object with the contents of args.
for (var i = 0; i < req.user.userListings.length; i++) {
if (req.user.userListings[i].listingId == req.params.listingId) {
User.update({
_id: req.user._id,
'userListings._id': req.user.userListings[i]._id
}, {
'userListings.isRead': args.isRead,
'userListings.isFavorite': args.isFavorite,
'userListings.isArchived': args.isArchived
}, function(err, user) {
res.send(user);
});
}
}
Here are the schemas:
var userListingSchema = new mongoose.Schema({
listingId: ObjectId,
isRead: {
type: Boolean,
default: true
},
isFavorite: {
type: Boolean,
default: false
},
isArchived: {
type: Boolean,
default: false
}
});
var userSchema = new mongoose.Schema({
userListings: [userListingSchema]
});
This find also doesn't work, which is probably the first issue:
User.find({
'_id': req.user._id,
'userListings._id': req.user.userListings[i]._id
}, function(err, user) {
console.log(err ? err : user);
});
which returns:
{ stack: [Getter/Setter],
arguments: [ 'path', undefined ],
type: 'non_object_property_call',
message: [Getter/Setter] }
That should be the equivalent of this mongo client call:
db.users.find({'userListings._id': ObjectId("4e44850101fde3a3f3000002"), _id: ObjectId("4e4483912bb87f8ef2000212")})
Running:
mongoose v1.8.1
mongoose-auth v0.0.11
node v0.4.10
when you already have the user, you can just do something like this:
var listing = req.user.userListings.id(req.params.listingId);
listing.isRead = args.isRead;
listing.isFavorite = args.isFavorite;
listing.isArchived = args.isArchived;
req.user.save(function (err) {
// ...
});
as found here: http://mongoosejs.com/docs/subdocs.html
Finding a sub-document
Each document has an _id. DocumentArrays have a special id method for looking up a document by its _id.
var doc = parent.children.id(id);
* * warning * *
as #zach pointed out, you have to declare the sub-document's schema before the actual document 's schema to be able to use the id() method.
Is this just a mismatch on variables names?
You have user.userListings[i].listingId in the for loop but user.userListings[i]._id in the find.
Are you looking for listingId or _id?
You have to save the parent object, and markModified the nested document.
That´s the way we do it
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
Profile.findById(req.params.id, function (err, profile) {
if (err) { return handleError(res, err); }
if(!profile) { return res.send(404); }
var updated = _.merge(profile, req.body);
updated.markModified('NestedObj');
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.json(200, profile);
});
});
};