Insert online shopping cart items into MongoDB using Mongoose - javascript

I am attempting to insert a cart of items as a JSON object into a MongoDB collection using a mongoose schema.
The customer's ID is getting stored (which comes from the User DB), but the cart items are not. Here is my code:
Sample order data contained in local variable app.js called cartData: { data:[] }:
{
data: [
item {
name: "Product Name 1",
price: '2.99',
sku: '13579',
count: 8
},
item {
name: 'Product Name 2',
price: '21.99',
sku: '24680',
count: 2
}
]
}
Cart.js (Cart Schema):
const mongoose = require("mongoose")
const CartSchema = new mongoose.Schema({
customerID: {
type: String,
required: true
},
cartContents: {
type: [Object]
},
date: {
type: Date,
default: Date.now
}
}, { collection: "ordersDB" })
const Cart = mongoose.model('Cart', CartSchema)
module.exports = Cart
app.js (Order Submit Code):
const Cart = require("../models/Cart")
const customerID = req.user.customerID //Acquired from user database
const newOrder = new Cart({
customerID,
cartData
})
newOrder.save()
.then(customer => {
req.flash("successful", "Your order has been submitted!")
res.redirect("/somepage")
})
.catch(err => console.log(err))
Result:
_id: abcd1234
> cart: Object
> type: Array
> <The Infinite Abyss Of Nothingness aka Empty>
customerID: "1234567890"
date: 2019-12-11T21:14:40.825+00:00
__v: 0
Any insight on this problem would be greatly appreciated.

Based on provided schema Mongoose expects you to pass a field called cartContents. Any other field not compatible with your schema will be ignored. To fix that just name your field explicitly:
const newOrder = new Cart({
customerID,
cartContents: cartData
})

Related

Mongoose is not populating the fields in MongoDB

When I run the following code, I get the object along with the populated fields logged on the console.
Screenshot
But, the fields have not been populated in the books collection. Can someone please help me figure this out?
const bookSchema = new Schema({
title: String,
genre: { type: Schema.Types.ObjectId, ref: "genre" },
author: { type: Schema.Types.ObjectId, ref: "author" },
numberInStock: { type: Number, default: 0 },
rating: Number,
yearPublished: Number,
dateAdded: { type: Date, default: Date.now },
liked: { type: Boolean, default: false },
});
const genreSchema = new Schema({ name: String });
const authorSchema = new Schema({ name: String });
const Book = model("book", bookSchema);
const Genre = model("genre", genreSchema);
const Author = model("author", authorSchema);
const books = [
{
title: "Sapiens",
genre: "632873144b0bbfc10ae1942d",
author: "632873e706fe265eaee77de3",
numberInStock: 6,
rating: 4.4,
yearPublished: 2011,
},
];
async function saveBook(b) {
let book = new Book(b);
book
.save()
.then((result) => {
populateBook(result._id);
})
.catch((err) => console.log("Error: ", err));
}
function populateBook(id) {
Book.findById(id)
.populate("genre")
.populate("author")
.exec((err, book) => {
if (err) {
console.log("Error: ", err);
return;
}
console.log(book);
});
}
books.forEach((b) => {
saveBook(b);
});
That's how population works, it only stores references to other documents in the database. At query time, and if you ask for it (using .populate()), Mongoose will retrieve the referenced documents and insert them into the "parent" document.
If you want the referenced documents to be stored in the database, you can't use population but have to use subdocuments.
However, this will limit the flexibility of your database, because if for example an author name needs to be changed, you need to change all the Book documents in your database to update the author's name. With population, you only need to change the Author document.

How to return an error when $addToSet does not add an item because it already exists in Mongoose?

I have the following schema which contains a property with an array:
const projectSchema = new mongoose.Schema(
{
title: {
type: String,
required: [true, "Please add a title"],
},
users: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
},
);
In my project controller, I'm trying to add users to this array without getting a duplicate user. So I use $addToSet. It works fine but it doesn't return an error when there is a duplicate user.
const project = await Project.findOneAndUpdate(
{ _id: id },
{ $addToSet: { users: userID } },
{ new: true }
);
How can I detect that it didn't add a user (because the user already exists in the array) and return an error?

Manipulating Data Array in React and Graphql

I'm attempting to manipulate this data in react with graphql. As you can see, I have this data or input in the graphql playground, and this is how I wanted the input to look:
In my frontend, I have a cartItem with an objects inside and array, including the product name, id, and so on. I wanted the input to look like the example I provided above. Is there a way to make that happen?
Codes and Data
This is how my cart's Item Data looks.
CartItem Data:
[
{
id: "6109401fd86d352a70e3694e",
name: "asasasasa",
sku: "sasa",
shippingTime: "1628812800000",
quantity: 1,
},
{
id: "61051c14f25d8830a8e238c0",
name: "Pringles Sour Cream & Onion Potato Crisps 158g",
sku: "sad89f79dsafs",
shippingTime: "1627084800000",
quantity: 1,
},
];
As stated in the preceding example, all I wanted was the product's id and quantity.
Order.js
const [cartItems, setCartItems] = useContext(CartContext);
const [createOrder, { data, loading }] = useMutation(CREATE_ORDER_MUTATION);
const qty = cartItems.map(({ quantity }) => {
return quantity;
});
const cartItemId = cartItems.map(({ id }) => {
return id;
});
function onSubmit() {
createOrder({
variables: {
qty: qty,
products: cartItemId,
paymentMethod: paymentMethod,
address: address,
},
})
}
Whenever I need to console someone. If you log the cartItemId, you'll get something like this:
Same goes with my qty.
Please let me know if you have any other questions or require any additional code, and I will gladly offer it.
Apollo Mutation:
const CREATE_ORDER_MUTATION = gql`
mutation createOrder(
$qty: Int!
$products: String!
$paymentMethod: String!
$address: String!
) {
createOrder(
orderedItems: [{ qty: $qty, products: $products }]
paymentMethod: $paymentMethod
address: $address
) {
id
orderedItems {
qty
products {
id
name
sku
description
}
}
}
}
`;
The code below will transform the cartItems into the desired result. You can loop through the cartItems and create an object with the required structure for each item.
const orderedItems = cartItems.map(({ id, quantity }) => {
return {
qty: quantity,
products: id,
};
});
Complete code will look something like this
const [cartItems, setCartItems] = useContext(CartContext);
const [createOrder, { data, loading }] = useMutation(CREATE_ORDER_MUTATION);
// Restructure the array to desired format
const orderedItems = cartItems.map(({ id, quantity }) => {
return {
qty: quantity,
products: id,
};
});
console.log(orderedItems); // To check if it looks correct
function onSubmit() {
createOrder({
variables: {
orderedItems: orderedItem,
paymentMethod: paymentMethod,
address: address,
},
})
}

Mongoose filter by nested reference

I have 3 mongoose schemas Employee, Team and Project. Employee has reference to the team and Team has reference to the Project. Is it possible to get all employees by project Id? I don't want to change schema or use Team model with populate.
const employeeSchema = mongoose.Schema({
email: { type: String, required: true, unique: true },
team: { type: mongoose.Schema.Types.ObjectId, ref: "Team" },
});
const teamSchema = mongoose.Schema({
name: { type: String, required: true },
employees: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
project: { type: mongoose.Schema.Types.ObjectId, ref: "Project" },
});
Below code throws cast error, id is a valid project id.
router.get("/:id/employees", checkAuth, (req, res, next) => {
const id = req.params.id;
console.log(id);
Employee.find({ team:{project:id}}).then((employees) => {
console.log(employees);
});
});
Yes it is possible to get all employees using project Id.but not using single query so you have to modify your function like this
const id = mongoose.Types.ObjectId(req.params.id);
Team.findOne({ project: id }, { _id: 1 }, function (err, docs) {
// Get the Team which match with project ID
Employee.find({ team: docs._id }, function (err, docs1) {
//Get all employee belongs to that team and project
console.log(docs1);
});
});

How to set _id to db document in Mongoose?

I'm trying to dynamically create _id's for my Mongoose models by counting the documents in the db, and using that number to create the _id (assuming the first _id is 0). However, I can't get the _id to set from my values. Here's my code:
//Schemas
var Post = new mongoose.Schema({
//_id: Number,
title: String,
content: String,
tags: [ String ]
});
var count = 16;
//Models
var PostModel = mongoose.model( 'Post', Post );
app.post( '/', function( request, response ) {
var post = new PostModel({
_id: count,
title: request.body.title,
content: request.body.content,
tags: request.body.tags
});
post.save( function( err ) {
if( !err ) {
return console.log( 'Post saved');
} else {
console.log( err );
}
});
count++;
return response.send(post);
});
I've tried to set the _id a number of different ways, but it's not working for me. Here's the latest error:
{ message: 'Cast to ObjectId failed for value "16" at path "_id"',
name: 'CastError',
type: 'ObjectId',
value: 16,
path: '_id' }
If you know what's going on, please let me know.
You either need to declare the _id property as part of your schema (you commented it out), or use the _id option and set it to false (you're using the id option, which creates a virtual getter to cast _id to a string but still created an _id ObjectID property, hence the casting error you get).
So either this:
var Post = new mongoose.Schema({
_id: Number,
title: String,
content: String,
tags: [ String ]
});
Or this:
var Post = new mongoose.Schema({
title: String,
content: String,
tags: [ String ]
}, { _id: false });
The first piece of #robertklep's code doesn't work for me (mongoose 4), also need to disabled _id
var Post = new mongoose.Schema({
_id: Number,
title: String,
content: String,
tags: [ String ]
}, { _id: false });
and this works for me
Create custom _id in mongoose and save that id as a mongo _id.
Use mongo _id before saving documents like this.
const mongoose = require('mongoose');
const Post = new mongoose.Schema({
title: String,
content: String,
tags: [ String ]
}, { _id: false });
// request body to save
let post = new PostModel({
_id: new mongoose.Types.ObjectId().toHexString(), //5cd5308e695db945d3cc81a9
title: request.body.title,
content: request.body.content,
tags: request.body.tags
});
post.save();
This works for me when saving new data for the schema. I used the exact code below in my project
new User(
{
email: thePendingUser.email,
first_name: first_name || thePendingUser.first_name,
last_name: last_name || thePendingUser.last_name,
sdgUser: thePendingUser.sdgUser,
sdgStatus: "active",
createdAt: thePendingUser.createdAt,
_id: thePendingUser._id,
},
{ _id: thePendingUser._id }
)

Categories