Store a mongodb document inside another document - mongodb

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);
}
);

Related

mongoose When I Use update it updates Nothing with status 200(success)

I use update Query for push some data in array in Mongodb and I use mongoose in nodeJs.Pplease anyone can help out from this.
Model Schema :
var mongoose = require('mongoose')
var Schema = mongoose.Schema;
var bcrypt = require('bcrypt')
var schema = new Schema({
email: { type: String, require: true },
username: { type: String, require: true },
password: { type: String, require: true },
creation_dt: { type: String, require: true },
tasks : []
});
module.exports = mongoose.model('User',schema)
So I use this schema and I want to push data in tasks array and here is my route code for pushing data.
Route For Update Data in Tasks:
router.post("/newTask", isValidUser, (req, res) => {
addToDataBase(req, res);
});
async function addToDataBase(req, res) {
var dataa = {
pName: req.body.pName,
pTitle: req.body.pTitle,
pStartTime: req.body.pStartTime,
pEndTime: req.body.pEndTime,
pSessionTime: req.body.pSessionTime,
};
var usr = new User(req.user);
usr.update({ email: req.user.email }, { $push: { tasks: dataa } });
console.log(req.user.email);
try {
doc = await usr.save();
return res.status(201).json(doc);
} catch (err) {
return res.status(501).json(err);
}
}
Here I create a async function and call that function in route but when I post data using postman it response with status code 200(success) but it updates nothing in my database.
Output screenshot:
as you can see in this image task : [].. it updates nothing in that array but status is success
I don't know why is this happening.
You can achieve this task easier using findOneAndUpdate method.
router.put("/users", isValidUser, async (req, res) => {
var data = {
pName: req.body.pName,
pTitle: req.body.pTitle,
pStartTime: req.body.pStartTime,
pEndTime: req.body.pEndTime,
pSessionTime: req.body.pSessionTime,
};
try {
const user = await User.findOneAndUpdate(
{ email: req.user.email },
{
$push: {
tasks: data,
},
},
{ new: true }
);
if (!user) {
return res.status(404).send("User with email not found");
}
res.send(user);
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});
Also I strongly suggest using raw / JSON data for request body, that's how most ui libraries (reactjs, angular) send data.
To be able to parse json data, you need to add the following line to your main file before using routes.
app.use(express.json());
TEST
Existing user:
{
"tasks": [],
"_id": "5e8b349dc285884b64b6b167",
"email": "test#gmail.com",
"username": "Kirtan",
"password": "123213",
"creation_dt": "2020-04-06T14:21:40",
"__v": 0
}
Request body:
{
"pName": "pName 1",
"pTitle": "pTitle 1",
"pStartTime": "pStartTime 1",
"pEndTime": "pEndTime 1",
"pSessionTime": "pSessionTime 1"
}
Response:
{
"tasks": [
{
"pName": "pName 1",
"pTitle": "pTitle 1",
"pStartTime": "pStartTime 1",
"pEndTime": "pEndTime 1",
"pSessionTime": "pSessionTime 1"
}
],
"_id": "5e8b349dc285884b64b6b167",
"email": "test#gmail.com",
"username": "Kirtan",
"password": "123213",
"creation_dt": "2020-04-06T14:21:40",
"__v": 0
}
Also as a side note, you had better to create unique indexes on username and email fields. This can be done applying unique: true option in the schema, but better to create these unique indexes at mongodb shell like this:
db.users.createIndex( { "email": 1 }, { unique: true } );
db.users.createIndex( { "username": 1 }, { unique: true } );
It's been awhile since I've done mongoose, but I'm pretty sure <model>.update() also actively updates the record in Mongo.
You use .update() when you want to update an existing record in Mongo, but you are instantiating a new User model (i.e. creating a new user)
try the following code instead for a NEW USER:
router.post('/newTask', isValidUser, (req, res) => {
addToDataBase(req,res)
})
async function addToDataBase(req, res) {
var dataa = {
pName: req.body.pName,
pTitle: req.body.pTitle,
pStartTime: req.body.pStartTime,
pEndTime: req.body.pEndTime,
pSessionTime: req.body.pSessionTime
}
// email field is already in `req.user`
var usr = new User({ ...req.user, tasks: [dataa] });
console.log(req.user.email);
try {
await usr.save();
return res.status(201).json(doc);
}
catch (err) {
return res.status(501).json(err);
}
}
Now, if you wanted to update an existing record :
router.post('/newTask', isValidUser, (req, res) => {
addToDataBase(req,res)
})
async function addToDataBase(req, res) {
var dataa = {
pName: req.body.pName,
pTitle: req.body.pTitle,
pStartTime: req.body.pStartTime,
pEndTime: req.body.pEndTime,
pSessionTime: req.body.pSessionTime
}
try {
await usr. updateOne({ email : req.user.email}, { $push: { tasks: dataa } });
return res.status(201).json(doc);
}
catch (err) {
return res.status(501).json(err);
}
}
For more info read: https://mongoosejs.com/docs/documents.html

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
}
]
}

Mongoose find by data field from schema into services

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...

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);
});
});
};