How to append data to existing array in mongodb in MERN stack - mongodb

I have an existing array which looks like this
{
_id: 5f14675a4fb8565fb89ec338,
name: 'sample5',
email: 'sample5#test.com',
rollno: 9,
city: [
{
_id: 5f14675a4fb8565fb89ec339,
cityname: 'Sample City 1',
citycode: '000000'
}
],
__v: 0
}
So I want to append the data to the existing array which is
city: [
{
_id: 5f14675a4fb8565fb89ec339,
cityname: 'Sample City 2',
citycode: '000002'
}
],
So my final db should look like this
{
_id: 5f14675a4fb8565fb89ec338,
name: 'sample5',
email: 'sample5#test.com',
rollno: 9,
city: [
{
_id: 5f14675a4fb8565fb89ec339,
cityname: 'Sample City 1',
citycode: '000000'
},
{
_id: 5f14675a4fb8565fb89ec339,
cityname: 'Sample City 2',
citycode: '000002'
},
],
__v: 0
}
For now I am just able to update my existing data where I show the cityname and citycode and if the user make any changes it is reflected in the database.
Code I am using to update the database
// Update Student
router.route('/update-student/:id').put((req, res, next) => {
studentSchema.findByIdAndUpdate(req.params.id, {
$set: req.body
}, (error, data) => {
if (error) {
return next(error);
console.log(error)
} else {
// $push:{
res.json(data)
console.log('Student updated successfully !')
// }
}
})
})
Schema structure
let studentSchema = new Schema({
name: {
type: String
},
email: {
type: String
},
rollno: {
type: Number
},
city: [{
cityname: {type: String},
citycode: {type: String},
}],
},
{
collection: 'students'
})
And then in routes it is updated using $push method
// Update Student
router.route('/update-student/:id').put((req, res, next) => {
studentSchema.findByIdAndUpdate(req.params.id, {
$push: req.body
}, (error, data) => {
if (error) {
return next(error);
console.log(error)
} else {
// $push:{
res.json(data)
console.log('Student updated successfully !')
// }
}
})
})
OUTPUT
[{_id: "5f12e5158be2503422bf6982", name: "sample1", email: "sample1#test.com", rollno: 1,…},…]
0: {_id: "5f12e5158be2503422bf6982", name: "sample1", email: "sample1#test.com", rollno: 1,…}
city: [{_id: "5f146fb84fb8565fb89ec33c", cityname: "city3", citycode: "12345"},…]
0: {_id: "5f146fb84fb8565fb89ec33c", cityname: "city3", citycode: "12345"}
citycode: "12345"
cityname: "city3"
_id: "5f146fb84fb8565fb89ec33c"
1: {_id: "5f15301f67c1992f4a233f77", cityname: "new city", citycode: "new code"}
citycode: "new code"
cityname: "new city"
_id: "5f15301f67c1992f4a233f77"
email: "sample1#test.com"
name: "sample1"
rollno: 1
__v: 0
_id: "5f12e5158be2503422bf6982"

Check out This answer you might need to use the $push in your query to achieve what you want.

SOLUTION
When the submit button is clicked. The array is stored in city as the schema is in this manner. This schema structure is there above. It is then passed to the db using axios.
onSubmit(e) {
e.preventDefault()
const studentObject = {
city: [{cityname: this.state.cityname, citycode: this.state.citycode}]
};
axios.put('http://localhost:4000/students/update-student/' + this.props.match.params.id, studentObject)
.then((res) => {
console.log(res.data)
console.log('Student successfully updated')
}).catch((error) => {
console.log(error)
})
// Redirect to Student List
this.props.history.push('/student-list')
}

Related

mongodb/mongoose + graphql When referencing a model with the id, the data is null

My apologies if this doesn't make too much sense, I am starting to get more comfortable with Mongodb using mongoosejs and also using graphql. I am trying to create a db that will contain transactions made by users, said transactions should be part of a specific category.
These are my typedefs:
type Auth {
token: ID!
user: User
}
type User {
_id: ID
email: String
expenses: [Expense]
}
type Category {
_id: ID
name: String
}
type Expense {
_id: ID
expenseName: String
expenseAmount: Float
expenseDate: String
category: Category
}
type Query {
me: User
users: [User]
user(email: String!): User
expenses(email: String!): [Expense]
expense(id: ID!): Expense
categories: [Category]
}
type Mutation {
login(email: String!, password: String!): Auth
addCategory(name: String!): Category
addUser(email: String!, password: String!, firstName: String!, lastName: String!): Auth
addExpense(expenseName: String!, expenseAmount: Float!, categoryId: ID!): Expense
}
And my resolver for the expense/transaction:
addExpense: async (parent, args, context) => {
if(context.user) {
const expense = await Expense.create({
expenseName: args.expenseName,
expenseAmount: args.expenseAmount,
category: args.categoryId,
});
await User.findByIdAndUpdate(
{ _id: context.user._id },
{ $push: { expenses: expense._id } },
{ new: true }
);
return expense;
}
throw new AuthenticationError("You must be logged in!");
}
Just in case you need it, these are my schemas:
For the user schema:
const userSchema = new Schema({
email: {
type: String,
required: true,
unique: true,
match: [/.+#.+\..+/, "Must match an email address!"],
},
password: {
type: String,
required: true,
minlength: [8, "Password must be at least 8 characters long!"],
},
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
expenses: [
{
type: Schema.Types.ObjectId,
ref: "Expense",
}
]
});
For the expense/transaction:
const expenseSchema = new Schema({
expenseName: {
type: String,
required: true,
minlenght: 1,
},
expenseAmount: {
type: Number,
required: true,
min: 0.01,
},
expenseDate: {
type: Date,
default: Date.now,
},
category: {
type: Schema.Types.ObjectId,
ref: "Category",
required: true,
}
});
For the category creation:
const categorySchema = new Schema({
name: {
type: String,
required: true,
},
});
So when I run it in apollo server after adding an expense/transaction, it shows everything but it will not show the name for the category, it will always show null:
"data": {
"me": {
"_id": "630a42ea7f7be79ba1d4114c",
"email": "admin#test.com",
"expenses": [
{
"_id": "630af7b795e5fd336ba708be",
"expenseName": "Mom",
"expenseAmount": 70,
"expenseDate": "1661663159375",
"category": {
"_id": "630af5fd2d4b15974802c026",
"name": null
}
},
{
"_id": "630af85695e5fd336ba708c2",
"expenseName": "Mom",
"expenseAmount": 70,
"expenseDate": "1661663318985",
"category": {
"_id": "630a432b7f7be79ba1d4114e",
"name": null
}
}
]
}
}
}
Could someone help me figure out what am I missing? Apologies if I am sharing too much

How do i push items into a Express.js scheme

I wonder how can i push an item into an array contained in a Express.js Scheme.
Here is the scheme i am trying to push items into:
const mongoose = require("mongoose") ;
const Post = new mongoose.Schema({
username: {type:String, required:true},
password: {type:String, required:true},
passwordHash: {type:String, required:true},
userOrders: [{orderId: String, orderItem:String}]
}, {
collection: 'users-data'
})
module.exports = mongoose.model("PostAccount", Post)
And my attempt to do it:
userForm.findOneAndUpdate(
{username : usernameDB },
{ $push:{userOrders :{orderId: id, orderItem: item}} },
function (error, success) {
if (error) {
console.log(error);
} else {
console.log(success);
}
});
Also here you can see the output i get:
{
_id: new ObjectId("62c73f91b853f687b507b069"),
username: 'admin3',
password: 'root',
passwordHash: '$2b$10$IEausr.hQzcRcFxhSOPAN.WyNY6gBHWEOr8db7Js3/iitcAC34ple', userOrders: [
{
orderId: null,
orderItem: null,
_id: new ObjectId("62c73f91b853f687b507b06a")
}
],
__v: 0
}

I cannot remove a subdocment in mongo Db?

I am trying to delete a subdocument from my users collection in Mongo Db, my best attempt to remove the subdocument is the the route below. However is does not work. I have been able to $unset the entire Favorite Movies array but I only want to delete one Item by its _id within the Favorite Movies Sub-Document. What am I doing Wrong.
// My Route That is supposed to Delete a Subdocument:
app.put('/Favorites/:UserName/delete/:_id',passport.authenticate('jwt', { session: false }), (req, res) => {
users.findOneAndUpdate({ UserName: req.params.UserName })
.then((user) => {
if (!user) {
res.status(400).send('ID: ' + req.params._id + ' was not found!!');
} else {
user.updateOne(
{UserName: req.params.UserName},
{
$pull: {
"FavoriteMovies": {
"ObjectId": req.params._id
}
}
})
res.status(200).send('ID: ' + req.params._id + ' was deleted!');
}
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
//Mongoose Model Schema for User in which the Subdocuemnt I want to delete is in Favorite Movies:
let usersSchema = mongoose.Schema({
_id: {type: Object},
UserName: {type: String, required: true},
Password: {type: String, required: true},
Email: {type: String, required: true},
Birthday: Date,
FavoriteMovies:{type: Object},
ImagePath: String
});
The User Object with Favorite Movies Subdocument in Postman- Raw:
[
{
"_id": 1650119097711,
"UserName": "robbies",
"Password": "$2b$10$UZmRBLZF0UGWrB1OrZVI2ePc7N1ae5sSZj0RlSU8WyRIRsfdE.yYW",
"Email": "rob#gmail.com",
"Birthday": "1988-05-05T00:00:00.000Z",
"FavoriteMovies": [
{
"ObjectId": 2009,
"Title": "The NoteBook",
"Genre": "Romance"
},
{
"ObjectId": 2001,
"Title": "Hacksaw Ridge",
"Genre": "Action"
}
],
"ImagePath": null,
"__v": 0
}
]

Mongoose: Get the data from 2 collections, like get products that have same category type like fruits

I am very new to mongoDB and mongoose and I also know questions like this has been already asked but still I didn't get any luck.
So what I am trying to do is I have 2 collections one is products and second is categories and I am trying to get the products that are of category type: fruits
product.model.js
const mongoose = require('mongoose')
const productSchema = new mongoose.Schema({
category: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Category'
},
name: {
type: String,
required: true,
unique: true
},
price: {
type: Number,
required: true
},
image: {
type: String,
required: true
},
description: {
type: String,
required: true
}
})
const Product = mongoose.model('Product', productSchema)
module.exports = Product
category.model.js
const mongoose = require('mongoose')
const categorySchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true,
lowercase: true
}
})
const Category = mongoose.model('Category', categorySchema)
module.exports = Category
products collecction
[ { _id: 5ffc9795355f3707ec326f51,
name: 'apple',
price: 80,
image: 'apple1.jpg',
description:
'Do you really need description for this ??',
category: 5ffc94e8a7542a37101a119c,
__v: 0 },
{ _id: 5ffd54409793c33b183376b8,
name: 'Beef',
price: 180,
image: 'beef1.jpg',
description: 'Don\'t you dare to ask about beef in india',
category: 5ffc94dda7542a37101a119b,
__v: 0 },
{ _id: 5ffd54969793c33b183376b9,
name: 'Mango',
price: 100,
image: 'mango1.jpg',
description:
'Have some manog because you cannot eat the bottle of slice like katrina kaif do, its crazy',
category: 5ffc94e8a7542a37101a119c,
__v: 0 } ]
categories collection
[ { _id: 5ffc947ea7542a37101a119a, name: 'vegitables', __v: 0 },
{ _id: 5ffc94dda7542a37101a119b, name: 'non-veg', __v: 0 },
{ _id: 5ffc94e8a7542a37101a119c, name: 'fruits', __v: 0 } ]
Now I want to the get the products whose category are fruits
I know I have to use aggregation and lookup for this I also tried but didn't get any luck, this is my code
const Product = require('./models/product')
const Category = require('./models/category')
const test = async () => {
try {
var query = [
{
$lookup: {
from: "product",
localField: "category",
foreignField: "_id",
as: "product"
}
}]
const productCate = await Product.aggregate(query)
console.log(productCate)
// const productCat = await Product.find().populate({
// path: 'category',
// match: {name: 'fruits'}
// }).exec()
// console.log(productCat)
}catch(e) {
}
}
test()
UPDATE-1
I also tried ppuplate but still didn't get the response as expected, this is my code:
const test = async () => {
try {
const productCat = await Product.find().populate({
path: 'category',
match: {name: 'fruits'}
}).exec()
console.log(productCat)
}catch(e) {
}
}
test()
this is my output
[ { _id: 5ffc9795355f3707ec326f51,
name: 'apple',
price: 80,
image: 'apple1.jpg',
description:
'Do you really need description for this, how dumb are you ??',
category: { _id: 5ffc94e8a7542a37101a119c, name: 'fruits', __v: 0 },
__v: 0 },
{ _id: 5ffd54409793c33b183376b8,
name: 'Beef',
price: 180,
image: 'beef1.jpg',
description: 'Don\'t you dare to ask about beef in india',
category: null,
__v: 0 },
{ _id: 5ffd54969793c33b183376b9,
name: 'Mango',
price: 100,
image: 'mango1.jpg',
description:
'Have some manog because you cannot eat the bottle of slice like katrina kaif do, its crazy',
category: { _id: 5ffc94e8a7542a37101a119c, name: 'fruits', __v: 0 },
__v: 0 } ]
Here I also get the beef that is fall under non-veg category but with the category null. Actually I only want the fruits category products.
you can following this code
const test = async () => {
try {
let categoryId = await Category.findOne({name:"fruits"}).select("_id")
const productCat = await Product.find({category:categoryId}).populate(
"category"
).lean()
console.log(productCat)
}catch(e) {
}
}
test()
you can do with with populate match without using aggregation:
Product.find().populate({
path: 'category',
match: { 'name': 'fruits' }
})
.exec()

findOneAndUpdate document with array

Two questions here.
What is the correct way to findOneAndUpdate when there is an array? The example below errors with err MongooseError [CastError]: Cast to embedded failed for value.
Should you arrays of objects become separate collections?
* Example *
var ProductSchema = new Schema({
_id: Schema.Types.ObjectId,
product_name: String
});
var purchaseOrderSchema = new Schema(
{
purchaseOrderNo: Number,
products: [ProductSchema]
}
);
const purchaseOrder = new PurchaseOrder(req.body);
PurchaseOrder.findOneAndUpdate(
{ _id: req.body._id },
{
$set: req.body,
$push: req.body.products
},
{ upsert: true, new: true }
)
.then((result) => {
console.log('result', result);
res.status(200).json(result);
})
.catch((err) => {
console.log('err', err);
res.status(500).json({ error: err });
});
const body = {
_id: 'skjdhflksjdf',
purchaseOrderNo: 1,
products: [
{
_id: '111',
product_name: 'Cup'
},
{
_id: '222',
product_name: 'Spoon'
}
]
}
In the ProductSchema the type of _id field to set to ObjectId. The product id 111 and 222 are not a valid ObjectId and it fails to cast it. You can update the type of _id in ProductSchema to Number for this to work
var ProductSchema = new Schema({
_id: Number,
product_name: String
});