Mongoose get value from embedded document - node.js

i have a scheme like this
var WFWorkItemDocument = new Schema({
id: { type: String, required: true, unique: true, default: uuid.v1 },
description: { type: String },
period: [{
id: { type: String, default: uuid.v1 },
start: { type: Date, default: Date.now }
due: { type: Number, integer: true },
new: { type: Number, integer: true },
}],
i want to get the period's due value for that i used a method like
WorkItem.findOne({ id: idUpdate }, function(err, WorkItem) {
if (err) {
console.log("invlaid id");
//return res.send(404, { error: 'invalid id' });
}
if (WorkItem) {
console.log("id");
console.log(WorkItem.period.due);
} else {
//res.send(404, new Error('Workitem not found'));
}
});
but it doesn't work how can i get the due value??
This is the result for console.log(WorkItem)

Change the schema to embed one object. Unless you need embedded array.
var WFWorkItemDocument = new Schema({
id: { type: String, required: true, unique: true, default: uuid.v1 },
description: { type: String },
period: {
id: { type: String, default: uuid.v1 },
start: { type: Date, default: Date.now }
due: { type: Number, integer: true },
new: { type: Number, integer: true },
},
And if you define it as an embedded array, you can access like :
WorkItem.period[index].due

Related

Mongoose $push whole array in database

I'm having an error on my database where the sub array that I push to my database is missing and created a new id which means it detects data pushed inside.
here's the data I pushed. (toDeliver array has 4 objects inside).
I'm trying to send the whole array along with the string outside of the array.
after the request here what I receive on my database which is mongoDB.
the object inside toDeliver array is incomplete and created a ObjectId.
but the string outside of array was save the database.
here's my schema.
const OwnerSchema = mongoose.Schema({
username: {
require: true,
type: String,
},
password: {
require: true,
type: String,
},
isAdmin: {
type: Boolean,
default: true,
},
store: [
{
product_identifier: {
type: String,
require: true,
},
productname: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
quantity: {
type: Number,
required: true,
},
categoryfilter: {
type: String,
required: true
},
description: {
type: String,
required: true,
},
specs: {
type: String,
required: true
},
imageBase64: {
type: String,
required: true,
},
timestamp: {
type: String,
required: true,
}
}
],
delivery: [
{
clientname: {
type: String,
required: true
},
address: {
type: String,
required: true
},
email: {
type: String,
required: true
},
number: {
type: Number,
required: true
},
toDeliver: [
{
product_identifier: {
type: String,
require: true,
},
productname: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
}
],
toDeliverPaidViaPaypal: [
{
product_identifier: {
type: String,
require: true,
},
productname: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
}
]
}
]
});
here's my backend.
export const delivery = async (req,res) => {
const { id } = req.params;
console.log(id);
console.log(req.body);
try {
if(!id) return res.status(404).json({ message: 'ID not found' });
await OwnerModels.findByIdAndUpdate(id,
{
$push: {
delivery:
{
clientname: req.body.delivery[0].clientname,
address: req.body.delivery[0].address,
email: req.body.delivery[0].email,
number: req.body.delivery[0].number,
toDeliver:
[{
product_identifier: req.body.delivery[0].toDeliver.product_identifier,
productname: req.body.delivery[0].toDeliver.productname,
price: req.body.delivery[0].toDeliver.price
}]
,
toDeliverPaidViaPaypal: []
}
}
},
{
new: true,
},(err,res)=> {
if(err) return console.log({ error: err });
console.log({ result: res.delivery });
}).clone();
} catch (error) {
res.status(500).json({ message: 'Server error' });
}
}
hope ya guys can help me. thank you
I think you need to add square brackets around the toDeliver object to make it an array like your console object:
$push: {
delivery: {
clientname: req.body.delivery[0].clientname,
address: req.body.delivery[0].address,
email: req.body.delivery[0].email,
number: req.body.delivery[0].number,
toDeliver: [{
product_identifier: req.body.delivery[0].toDeliver.product_identifier,
productname: req.body.delivery[0].toDeliver.productname,
price: req.body.delivery[0].toDeliver.price
}],
toDeliverPaidViaPaypal: []
}
}
Also add "_id: false" to toDelivery in your schema to repress id from being generated for the sub-object:
toDeliver: [
{
product_identifier: {
type: String,
require: true,
},
productname: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
_id: false,
}
],

Model.find is not a function mongoose

I have a mini casino game and have a mongoose model defined as following:
const jackpotSchema = mongoose.Schema({
round_id: {
type: String,
default: uniqid(),
required: true,
},
createdAt: {
type: Date,
required: true,
default: Date.now
},
closedAt: {
type: Date,
},
startedAt: {
type: Number,
},
roundSecret: {
type: String,
required: true,
},
random_org_hash: {
type: String,
},
random_org_obj: {
type: String
},
roundSecretHash: {
type: String,
},
winningPercentage: {
type: Number,
// required: true,
// first 5 characters of the secret hash, converted into decimal then divided by 10K
},
publicHash: {
type: String,
required: true,
// SHA-256 roundSecret + winningPercentage
},
finalHash: {
type: String,
},
winningTicket: {
type: Number,
},
winningDepositIndex: {
type: Number,
},
deposits: [{
uid: {
type: String,
required: true,
},
user: {
type: String,
required: true,
},
nonce: {
type: Number,
},
amount: {
type: Number,
required: true,
},
user_avatar: {
type: String,
},
ticketRangeMin: {
type: Number,
required: true,
},
ticketRangeMax: {
type: Number,
required: true,
},
referral: {type: String},
timestamp: {type: Date},
timestamp_readable: {type: String}
}],
total: {
type: Number,
required: true,
default: 0,
},
totalTickets: {
type: Number,
default: 0,
},
winner: {
type: String,
default: "",
},
winner_avatar: {
type: String,
},
active: {
type: Boolean,
default: true,
required: true,
},
open: {
type: Boolean,
required: true,
default: true,
},
roundTime: {
type: Number,
// default: potConfig.potLength,
default: 20000,
},
success: {
type: Boolean,
},
fee: {
type: Number,
default: potConfig.potFee,
}
})
module.exports = mongoose.model("Jackpot", jackpotSchema)
When running my app locally, I experience no errors.
However when running on a ubuntu production environment, I get the following error:
Jackpot.find is not a function
The stack trace says that the error is coming from db_utils.js
which looks like the following:
const Jackpot = require("./models/Jackpot");
...
async retrieveStats () {
var jackpots = await Jackpot.find().lean();
}
I have checked to see whether my module.exports was defined correctly, and it is. Not sure why this error is happening.
My local and production node versions match.
12.18.4
Don't you need to do
const jackpotSchema = new mongoose.Schema({...})
instead of
const jackpotSchema = mongoose.Schema({...})

How to delete the referenced document in one collection and its record from the referred other collection

In my NodeJS API and MongoDB, I'm trying to delete a record which is a reference to another collection.
What I would like to do is to delete the referred objectId and the records related to the other collection which is referred.
I have 2 models Profiles and Posts and I want to delete the same one post from Profile and Post collection.
I was able to delete the reference id in Profile but I don't know how to delete also the record from Posts collection.
I tried this:
async delete(req, res) {
try {
// Match with username and pull to remove
await Profile.findOneAndUpdate(
{ _id: res.id._id },
{ $pull: { posts: req.params.postId } },
err => {
if (err) {
throw new ErrorHandlers.ErrorHandler(500, err);
}
res.json({ Message: "Deleted" });
}
);
} catch (error) {
res.status(500).send(error);
}
}
And my 2 models:
// Here defining profile model
// Embedded we have the Experience as []
const { Connect } = require("../db");
const { isEmail } = require("validator");
const postSchema = {
type: Connect.Schema.Types.ObjectId,
ref: "Post"
};
const experienceSchema = {
role: {
type: String,
required: true
},
company: {
type: String,
required: true
},
startDate: {
type: Date,
required: true
},
endDate: {
type: Date,
required: false
},
description: {
type: String,
required: false
},
area: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
},
username: {
type: String,
required: false
},
image: {
type: String,
required: false,
default: "https://via.placeholder.com/150"
}
};
const profileSchema = {
firstname: {
type: String,
required: true
},
surname: {
type: String,
required: true
},
email: {
type: String,
trim: true,
lowercase: true,
unique: true,
required: [true, "Email is required"],
validate: {
validator: string => isEmail(string),
message: "Provided email is invalid"
}
},
bio: {
type: String,
required: true
},
title: {
type: String,
required: true
},
area: {
type: String,
required: true
},
imageUrl: {
type: String,
required: false,
default: "https://via.placeholder.com/150"
},
username: {
type: String,
required: true,
unique: true
},
experience: [experienceSchema],
posts: [postSchema],
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
}
};
const collectionName = "profile";
const profileSchemaModel = Connect.Schema(profileSchema);
const Profile = Connect.model(collectionName, profileSchemaModel);
module.exports = Profile;
const { Connect } = require("../db");
const reactionSchema = {
likedBy: {
type: String,
unique: true,
sparse: true
}
};
const postSchema = {
text: {
type: String,
required: true,
unique: true,
sparse: false
},
profile: {
type: Connect.Schema.Types.ObjectId,
ref: "Profile",
},
image: {
type: String,
default: "https://via.placeholder.com/150",
required: false
},
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
},
reactions: [reactionSchema],
comments: {
type: Connect.Schema.Types.ObjectId,
ref: "Comment",
required: false
}
};
const collectionName = "post";
const postSchemaModel = Connect.Schema(postSchema);
const Post = Connect.model(collectionName, postSchemaModel);
module.exports = Post;
Just add a query to remove the post after pulling it's ID from the profile collection:
async delete(req, res) {
try {
// Match with username and pull to remove
await Profile.findOneAndUpdate(
{ _id: res.id._id },
{ $pull: { posts: req.params.postId } },
// You don't need an error callback here since you are
// using async/await. Handle the error in the catch block.
);
await Posts.remove({ _id: req.params.postId });
} catch (error) {
// This is where you handle the error
res.status(500).send(error);
}
}

mongoosejs findByIdAndUpdate a best way

I'm wondering if there a best way to do this:
/**
* Article Schema
*/
var PostSchema = new Schema({
title: {
type: String,
required: true,
trim: true
},
author:{
type: String,
required: true,
default: 'whisher'
},
slug: {
type: String,
index: { unique: true }
},
body: {
type: String,
required: true,
trim: true
},
avatar:{
type: String,
required: true
},
status: {
type: String,
required: true,
trim: true
},
created: {
type: Date,
required: true,
default: Date.now
},
published: {
type: Date,
required: true
},
categories: {
type: [String]
},
tags: {
type: [String],
required: true,
index: true
},
comment: {
type: Schema.Types.ObjectId,
ref: 'CommentSchema'
},
meta: {
votes: {
type: Number,
default: 0
},
comments: {
type: Number,
default: 0
}
}
});
/**
* Comment Schema
*/
var CommentSchema = new Schema({
post_id: {
type: Schema.Types.ObjectId,
ref: 'Post',
required: true
},
author:{
type: String,
required: true
},
email:{
type: String,
required: true
},
web:{
type: String
},
body: {
type: String,
required: true,
trim: true
},
status: {
type: String,
required: true,
default: 'pending'
},
created: {
type: Date,
required: true,
default: Date.now
},
meta: {
votes: Number
}
});
/**
* Create a comment
*/
exports.create = function(req, res) {
var comment = new Comment(req.body);
comment.save(function(err) {
if (err) {
return res.jsonp(500,{ error: 'Cannot save the comment' });
}
Post.findById(comment.post_id).exec(function(err, post) {
if (err) {
return res.jsonp(404,{ error: 'Failed to load post with id ' + comment.post_id });
}
if (!post) {
return res.jsonp(404,{ error: 'Failed to load post with id ' + comment.post_id });
}
post.meta.comments = post.meta.comments++;
post.save(function(err) {
if (err) {
return res.jsonp(500,{ error: 'Cannot update the post' });
}
res.jsonp(200,comment);
});
});
});
};
Btw I just looking at http://mongoosejs.com/docs/api.html#model_Model.findByIdAndUpdate
but like this:
Model.findByIdAndUpdate(comment.post_id, { post.meta.comments: post.meta.comments++ })
doesnt work
I think you need to use the $inc operator to increment the comment count like this...
Post.findByIdAndUpdate(comment.post_id, { $inc: {"meta.comments" : 1} }, callback);

Mongoose - Cast to ObjectId failed for value "[object Object]" at path _id

I have the below schema:
var StorySchema = new Schema({
title: { type: String, required: true },
users: {
id: { type: Schema.ObjectId, ref: 'users' },
creator: { type: Boolean }
},
maxlines: { type: Number, default: '10'},
lines: {
text: { type: String },
entered_at: { type: Date },
user: {
id: { type: Schema.ObjectId, ref: 'users' }
}
},
created_date: { type: Date, default: Date.now },
updated_date: { type: Date, default: Date.now },
})
I've got the below which does the query:
exports.view = function (req, res) {
Stories
.findOne({
_id: req.params.id
})
/*.populate('users') */ **<-- If I uncomment this I get the error**
.exec(function (err, story) {
if (err) {
res.json(200, {
success: "false",
message: err.message
})
} else if (story) {
res.json({
sucess: "true",
message: story
})
} else {
res.json(200, {
sucess: "false",
message: "story not found"
})
}
})
}
As above if I add .populate('users') it flags the below error:
{
"success": "false",
"message": "Cast to ObjectId failed for value \"[object Object]\" at path \"_id\""
}
I'm calling /view/51fc2e02576f2dc058000001 (which is an Object ID of the stories table), without the .populate('users') if I call the URL it brings back the document.
The users -> id value is populated with ObjectId("51fbe87ec137760025000001") - which is a valid _id in the users collection
I cannot see what I'm missing?
Added User Schema
var UserSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
username: { type: String, required: true, unique: true },
provider: { type: String, required: true, enum: ['local', 'facebook'] },
password: { type: String, required: true },
avatar: { type: String, default: 'http://i.imgur.com/1PtcFos.jpg' },
gender: { type: String, required: true, uppercase: true, enum: ['M', 'F'] },
facebook: {
id: { type: String },
token: { type: String },
token_expiry: { type: Date }
},
device: {
token: { type: String },
type: { type: String, enum: ['ios', 'android'] },
badge: { type: Number },
id: { type: String },
created_date: { type: Date, default: Date.now },
updated_date: { type: Date, default: Date.now }
},
created_date: { type: Date, default: Date.now },
updated_date: { type: Date, default: Date.now }
})
I think you can only do .populate('users.id'). Populate is to use the reference Object to replace the id field. Please take a look at the doc.

Resources