mongoose .push embedded docs in an embedded model? - node.js

Would like to .push fields of an embedded structure into an embedded model document on a .push method.
http://mongoosejs.com/docs/2.7.x/docs/embedded-documents.html
The console errors this though: SyntaxError: Unexpected token .
..for pushing bar.this : req.body.this, when concatenating for the embed in the embedded model
The models look like this:
var OneModel = new Schema({
foo: String,
bar: {
this : String,
that : Number,
}
});
var TwoModel = new Schema({
foo: String,
bar: {
this : String,
that : Number,
},
modelone: [OneModel]
});
And the NodeJS API looks this:
var ModelsOneTwo = require('./app/models/modelsonetwo');
router.route('/modeltwo/:modeltwo_id')
// update TwoModel with this _id
//(accessed at PUT http://localhost:4200/api/v1/modeltwo/:modeltwo_id)
.put(function(req, res) {
ModelsOneTwo.findById(req.params._id, function(err, modeltwo) {
if (err)
res.send(err);
// embedded document updating
// http://mongoosejs.com/docs/2.7.x/docs/embedded-documents.html
modeltwo.modelone.push({
foo : req.body.foo,
bar.this : req.body.this,
bar.that : req.body.that
});
// save the modeltwo, and check for errors
modeltwo.save(function(err) {
if (err)
res.send(err);
res.json({ message: req.params.modeltwo_id + ' ' + req.body.foo });
});
});
});

To set the properties of bar in the model, you'll have to create the additional Object for it:
modeltwo.modelone.push({
foo : req.body.foo,
bar : {
this : req.body.this,
that : req.body.that
}
});
This is similar to how it was defined in the schema:
var OneModel = new Schema({
foo: String,
bar: {
this : String,
that : Number,
}
});

Related

Trying to update a field of a single object whilst also pushing to an array nodejs mongodb

Within this post function i am trying to award a badge and then after the badge has been awarded within an array to the usermodel i am trying to update a separate field in the user doc which i have named as points, the udoc.total points currently works however after the call is finished the users total points do not update and stay as 0
Usermodel schema -
var schema = new Schema({
email : {type:String, require:true},
username: {type:String, require:true},
password:{type:String, require:true},
creation_dt:{type:Date, require:true},
diabeticType:{type:String, require:true},
badges: [Badges],
totalPoints: {type:Number, require:true},
glucoseReading : [
{
bloodGlucoseLevel : {
type : String,
required : "Required"
},
dosageTime : {
type : String,
},
unitsOfInsulinForFood : {
type : String,
},
correctionDose : {
type : String,
},
creation_dt :{
type : String,
}
}
]
});
and then this is the post command where the badge is added to the users profile however the total points do not update
router.post("/:id/badge/:bid", function (req, res){{'useFindAndModify', false}
Badgemodel.findById(req.params.bid).then(doc => {
if(!doc)
{
return res.status(404).end();
}
else
{
var awardBadge = doc;
Usermodel.findByIdAndUpdate(req.params.id,
{$push : {badges : awardBadge}},
{safe : true, upsert: true}).then(udoc =>{
if(!doc)
{
return res.status(404).end();
}
else
{
console.log(udoc);
console.log(udoc.totalPoints);
udoc.totalPoints = udoc.totalPoints + awardBadge.value;
console.log(udoc.totalPoints);
return res.status(200).end();
}
})
}
})
})
I think you have an error in your User Schema.
You are trying to reference a array of documents of the Badges collection in your User Schema definition at badges: [Badges],.
But when you reference a doc from an other collection in mongoose the syntax is different.
Checkout the mongoose docs.
The schema should look like this:
badges: [{
type: Schema.Types.ObjectId,
ref: "UserModel" // or whatever the Model name is
}]
see also
https://mongoosejs.com/docs/api/schematype.html#schematype_SchemaType-ref
Answer- I was storing the value for total points into a variable and this variable was not being sent back to the users info. I updated code by adding in another findbyidandupdate and included the $set function to update the users total points to the value of the variable udoc.total points.
router.post("/:id/badge/:bid", function (req, res){{'useFindAndModify', false}
Badgemodel.findById(req.params.bid).then(doc => {
if(!doc)
{
return res.status(404).end();
}
else
{
var awardBadge = doc;
Usermodel.findByIdAndUpdate(req.params.id,
{$push : {badges : awardBadge}},
{safe : true, upsert: true}).then(udoc =>{
if(!doc)
{
return res.status(404).end();
}
else
{
console.log(udoc);
console.log(udoc.totalPoints);
udoc.totalPoints = udoc.totalPoints + awardBadge.value;
Usermodel.findByIdAndUpdate({_id: req.params.id}, {$set: {totalPoints : udoc.totalPoints} }).then(doc => {
if(!doc)
{
return res.status(404).end();
}
else
{
return res.status(200).end();
res.send(doc);
}
})
console.log(udoc.totalPoints);
return res.status(200).end();
res.send(doc);
}
})
}
})
})

insert and insertOne not a function and update not creating mongo ID

I thought I could read my way to this solution, but I cant see what im doing wrong.
Here is my model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var inspectSchema = new Schema({
_id: Object, // Mongo ID
property: String, // Property ID
room: String, // The room Name
item: Array // The Items text
});
module.exports = mongoose.model('inspectModel', inspectSchema, 'inspect');
And here is where I try to insert or insertOne
var inspectModel = require('../../models/inspectModel');
var inspectTable = mongoose.model('inspectModel');
inspectTable.insert(
{
"property" : inspectRecord.property,
"room" : inspectRecord.room,
"item" : inspectRecord.item
},
function (err, res) {
if (err) { return reject({err:true, err:"addInspect ERROR" + err}) }
else {
show("=====RESOLVE addInspect=====")
return resolve();
}
})
I tried
inspectTable.insert
inspectModel.insert
inspectTable.insertOne
inspectModel.insertOne
No matter what I always get
TypeError: inspectTable.insert is not a function
I also tried just update with { upsert: true } but then the mongo ID becomes null.
Any ideas?
The method you're looking for is create:
inspectTable.create(
{
"property" : inspectRecord.property,
"room" : inspectRecord.room,
"item" : inspectRecord.item
}, ...
However, your schema definition of _id: Object is likely wrong. Just leave any definition of _id out of your schema and it will use the default ObjectId, which is likely what you want.
You can try this
var insert_table = new inspectTable(
{
"property" : inspectRecord.property,
"room" : inspectRecord.room,
"item" : inspectRecord.item
});
insert_table.save(function (err, res) {
if (err) { return reject({err:true, err:"addInspect ERROR" + err}) }
else {
show("=====RESOLVE addInspect=====")
return resolve();
}
});

Mongoose saving for populate

I'm new to Mongoose and Nodejs developement in general and I've got a bit of confusion around how to properly set up saving my records. Here are my two schemas:
Download
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var downloadSchema = Schema({
title : String,
description : String,
_project : { type: Schema.Types.ObjectId, ref: 'Project' }
});
module.exports = mongoose.model('Download', downloadSchema);
Project
...
var projectSchema = Schema({
name : String,
url : String,
pwd : String,
_downloads : [{type: Schema.Types.ObjectId, ref: 'Download' }]
});
module.exports = mongoose.model('Project', projectSchema);
This appears to be working correctly. The documentation explains my use-case of saving a download and linking a project, but I'm not sure how to properly populate the Project._downloads. Here's what I've done:
Express route handler:
function createDownload(req, res) {
// the Project Id is passed in the req.body as ._project
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
var dload = new Download(dldata);
dload.save( function (err, download) {
project._downloads.push(download._id);
project.save( function(err){
var msg = {};
if(err) {
msg.status = 'error';
msg.text = err;
}else {
msg.status = 'success';
msg.text = 'Download created successfully!';
}
res.json(msg);
});
});
});
}
This seems overcomplicated to me. Am I supposed to be manually pushing to the ._downloads array, or is that something Mongoose is supposed to handle internally based on the schema? Is there a better way to achieve it so that I can do:
Download.find().populate('_project').exec( ...
as well as:
Project.findOne({_id : _projectId}).populate('_downloads').exec( ...
According to the mongoose docs there are 2 ways to add subdocs to the parent object:
1) by using the push() method
2) by using the create() method
So I think that your code can be a bit simplified by eliminating the operation of saving a new Download item:
function createDownload(req, res) {
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
// handle error
project._downloads.push(dldata);
project.save(function(err) {
// handle the result
});
});
}
or
function createDownload(req, res) {
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
// handle error
project._downloads.create(dldata);
project.save(function(err) {
// handle the result
});
});
}

Removing a blog reference from a tag

I'm working on an application in Node with Mongoose where you're able to post blog entries and tag them. When a blog entry is deleted, I want to remove it's reference from the blog, and here's where I need help.
Below is the route for deleting a blog entry, but I get "TypeError: Cannot call method 'find' of undefined" when I try to delete a blog entry, so I guess my code below is wrong.
app.post('/blog/delete/:id', function(req, res){
model.BlogPost.findById(req.params.id, function (err, blog){
if (err) {
console.log(err);
// do something
}
blog.remove(function(err) {
console.log(err);
// do something
});
var query = model.Tag.find( { blogs: { $in : blog } } );
query.exec(function (err, tags) {
if (err) {
console.log(err);
// do something
}
tags.remove();
res.redirect('back');
});
});
});
Model for blog entries:
var BlogPostSchema = new Schema({
name : String,
type : String,
author : ObjectId,
title : String,
body : String,
buf : Buffer,
date: { type: Date, default: Date.now },
comments : [CommentSchema],
meta : {
upvotes : Number,
downvotes : Number,
// points : { type Number, default: },
favs : Number,
uniqueIPs : [String],
tags : [String]
}
});
modelObject.BlogPost = mongoose.model('BlogPost', BlogPostSchema);
Model for tags:
var TagSchema = new Schema({
name : String
, blogs : [String]
});
modelObject.TagSchema = TagSchema;
modelObject.Tag = mongoose.model('Tag', TagSchema);
Hard to tell with out line numbers, but looks like model.Tag may be undefined.
side note: you probably don't want to remove the tags unless the blog was found and removed successfully.

Add document to an embedded document array

I'm trying to add an embedded document to an existing document field. I found one fitting answer with the search but I'm running into errors. I'm using node.js, Express and Mongoose.
My database schemas:
var entry = new Schema({
name : { type : String, required : true},
description : { type : String, default: ""},
});
var compo = new Schema({
name : String,
description : String,
entries : [entry]
});
And I'm trying to update the entries array with the following code
var entry = new entryModel();
entry.name = "new name";
entry.description= "new description";
compoModel.findOne(query, function (err, item) {
if (item) {
item.entries.push(entry);
item.save(function (err) {
if (!err) {
log.debug('Entry added successfully.');
} else {
log.error("Mongoose couldn't save entry: " + err);
}
});
}
});
It yields an error: TypeError: Object.keys called on non-object
What have I missed?
So I managed to get it working via the Model.update method by simply adding a new object to the compo.entries list and calling compoModel.update.
My similar issue (same error) was solved by clearing the sub-document array. It was populated prior to the definition of the sub-document scheme. At least this is what i think happened.
E.g.:
var token = new Schema( { value: String, expires: Date } )
var user = new Schema( { username: String, tokens: [token] } )
.. and, prior to defining the 'token' scheme i had entries such as:
{ username: 'foo', tokens: ['123456'] }
.. so, clearing tokens did it for me.
user.tokens = []
user.save()

Resources