Create MongoDB new collection with json inside the schema - node.js

I try to create new collection with mongodb.
I wrote the MongoDB shcema, Nodejs+express code and everything work fine until I send parameters with Json inside them.
I was created this schema (and also more code under this schema) but its not work and I got error:
const partySchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
title: { type: String, required: true },
datetime: { type: Date, required: true },
location: {
scraping_location: { type: String, required: true },
display_location: { type: String, required: false },
city: { type: String, required: false },
adress: { type: String, required: false },
area: { type: String, required: false }
},
picture: { type: String, required: true },
url: { type: String, required: true },
affiliate_url: { type: String, required: true },
music_by: {type: [], required: false },
music_type: {type: [], required: false },
min_age_for_men: {type: Number, required: true },
min_age_for_women: {type: Number, required: true },
status_check: {type: Boolean, default: false },
tags: {
concept: { type: String, required: false },
free_text: { type: [], required: false }
},
producer_id: { type: String, required: false },
});
and the code that I wrote with nodejs+express is this:
const { title, datetime, location, picture, url, affiliate_url, music_by, music_type, min_age_for_men, min_age_for_women, tags, producer_id } = req.body;
const party = new Party({
_id: new mongoose.Types.ObjectId(),
title,
datetime,
location: { scarping_location: location.location_scarping },
picture,
url,
affiliate_url,
music_by,
music_type,
min_age_for_men,
min_age_for_women,
tags,
producer_id
});
party.save().then(() => {
res.status(200).json({
message: 'Create a new user'
})
}).catch(error => {
res.status(500).json({
error
})
});
when I send reqeust to the api with this body:
{
"title": "test",
"datetime": "2002-07-15T10:00:00+0300",
"location": {
"location_scarping": "new york"
},
"picture": "test.jpg",
"url": "https://google.com",
"affiliate_url": "https://google.com",
"min_age_for_men": 18,
"min_age_for_women": 16
}
I got this error:
{
"error": {
"errors": {
"location.scraping_location": {
"name": "ValidatorError",
"message": "Path `location.scraping_location` is required.",
"properties": {
"message": "Path `location.scraping_location` is required.",
"type": "required",
"path": "location.scraping_location"
},
"kind": "required",
"path": "location.scraping_location"
}
},
"_message": "Party validation failed",
"name": "ValidationError",
"message": "Party validation failed: location.scraping_location: Path `location.scraping_location` is required."
}
}
why its happend?

Looks like this is just a typo, from your schema:
scraping_location: { type: String, required: true }
You're trying to insert: location_scarping not location_scraping
"location_scarping": "new york"
Hopefully that fixes it.

Related

Issue when trying to store some data in a MongoDB data model

I want to store some data in the following MongoDB model:
import mongoose from 'mongoose';
const orderSchema = mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User',
},
orderItems: [
{
name: { type: String, required: true },
qty: { type: Number, required: true },
image: { type: String, required: true },
price: { type: Number, required: true },
product: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Product',
},
},
],
shippingAdress: {
address: { type: String, required: true },
city: { type: String, required: true },
postalCode: { type: String, required: true },
state: { type: String, required: false },
country: { type: String, required: true },
},
paymentMethod: {
type: String,
required: true,
},
paymentResult: {
id: { type: String },
status: { type: String },
update_time: { type: String },
email_address: { type: String },
},
taxPrice: {
type: Number,
required: true,
default: 0.0,
},
shippingPrice: {
type: Number,
required: true,
default: 0.0,
},
totalPrice: {
type: Number,
required: true,
default: 0.0,
},
isPaid: {
type: Boolean,
required: true,
default: false,
},
paidAt: {
type: Date,
},
isDelivered: {
type: Boolean,
required: true,
default: false,
},
deliveredAt: {
type: Date,
},
},
{ timestamps: true }
);
const Order = mongoose.model('Order', orderSchema);
export default Order;
But I am not able to post the following sample data to the database
{
"orderItems": [
{
"product": "6060f2eb6bea3f2280c08a4c",
"name": "Airpods Wireless Bluetooth Headphones",
"image": "/images/airpods.jpg",
"price": 89.99,
"qty": 3
}
],
"user": "6060f2eb6bea3f2280c08a4b",
"shippingAddress": {
"address": "1st Avenue Main St",
"city": "Boston",
"postalCode": "02011",
"country": "USA"
},
"paymentMethod": "Stripe",
"itemsPrice": 269.97,
"taxPrice": 40.50,
"shippingPrice": 20.00,
"totalPrice": 330.47
}
as I get the following error:
By the way I am trying to get that done through Postman
"Order validation failed: shippingAdress.country: Path shippingAdress.country is required., shippingAdress.postalCode: Path shippingAdress.postalCode is required., shippingAdress.city: Path shippingAdress.city is required., shippingAdress.address: Path shippingAdress.address is required."
You have a typo in your Model shippingAdress. It should be shippingAddress.

updating a nested field in mongodb not working

I have a model which has a field with nested fields, when I try to update the field it doesn't work. it still remail=ns the same. Below is the code with further explanations.
i have a model below
const mongoose = require('mongoose')
const placeSchema = new mongoose.Schema({
owner: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
typeof: {
type: String,
required: true,
enum: ["studio", "hall",
"house", "mansion",
"field", "room",
"restaurant", "school",
"church", "beach", "warehouse",
"others"
]
},
location: {
type: String,
required: true,
trim: true
},
time: {
alwaysopen: {
type: Boolean,
required: true,
default: false
},
open: {
type: String
},
close: {
type: String
}
},
idealfor: [{
type: String,
required: false,
enum: ["reception", "production",
"meeting", "performance",
"dinner", "wedding",
"party", "conference"
]
}],
rooms: {
type: Number,
required: false,
trim: true
},
toilet: {
type: Number,
required: false,
trim: true
},
price: {
type: Number,
required: true,
trim: true
},
amenities: [{
type: String,
required: false,
enum: ["electricity", "a/c",
"wifi", "sound system",
"private entrance",
"kitchen", "large table", "tv",
"green screen", "Stage",
"changing room", "makeup room",
"lounge", "soundproof"
]
}],
accessibility: [{
type: String,
required: false,
enum: ["wheelchair", "Elevator",
"on-site parking", "parking near by",
"Stairs"
]
}],
isOpen: {
type: Boolean,
required: false,
default: true
},
phonenumber: {
type: String,
required: true,
trim: true
},
}, {
timestamps: true
})
the problem is that when i try to update the time.alwaysopen field from false to true, id doesn't work.
below is the update route
// Edit a place
router.patch('/api/place/:id', isVerified, async (req, res) => {
const updates = Object.keys(req.body)
const allowedUpdates = ["title", "description", "maxguest", "size", "isOpen", "rules", "rooms", "toilet", "price", "phonenumber", "location", "typeof", "time", "time.alwaysopen", "time.open", "time.close"]
const isValidOperation = updates.every((update) => allowedUpdates.includes(update))
if (!isValidOperation) {
return res.status(404).send({ error: 'Invalid updates!' })
}
try {
const place = await Place.findOne({ _id: req.params.id, owner: req.user._id })
if (!place) {
return res.status(404).send({ "message": "place does not exist" })
}
updates.forEach((update) => place[update] = req.body[update])
await place.save()
res.status(201).send({place, "message": "successfully updated" })
} catch (e) {
res.status(400).send({ "message": "failed to update" })
}
})
and below is the patch json request i make
{
"time.alwaysopen": false
}
after sending the patch request, i still get the vaue of the time.alwaysopen to be true, but updating the field is fine.
below is the response i get
{
"place": {
"time": {
"alwaysopen": true
},
"idealfor": [
"production",
"wedding"
],
"amenities": [
"electricity",
"a/c",
"Stage"
],
"accessibility": [],
"unavailabledate": [],
"isOpen": true,
"img": true,
"_id": "604028e717314039402c2c10",
"typeof": "studio",
"location": "good news church, olufemi street, surulere, Lagos, Nigeria",
"rooms": 2,
"toilet": 2,
"price": 1000,
"phonenumber": "+2348125580085",
"owner": "603e6b494e0df045745066a7",
"createdAt": "2021-03-04T00:25:11.413Z",
"updatedAt": "2021-03-04T01:19:14.867Z",
"__v": 0,
"description": "the famous hotel",
"title": "Royal habiscus edited"
},
"message": "successfully updated"
}
Please, what could be the problem?

How to merge/partial update on sub document which is an array

const projectSchema = mongoose.Schema({
title: { type: String, required: true, trim: true },
projectId: { type: String, required: true, trim: true, unique: true },
company: { type: mongoose.Schema.Types.ObjectId, ref: 'Company', required: true },
description: { type: String, trim: true },
remark: { type: String, trim: true },
active: { type: Boolean, required: true },
participants: [{
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
active: { type: Boolean, required: true },
timeSpent: [{
date: { type: Date, required: true },
hour: { type: Number, required: true }
}]
}]
});
I've searched through a lot of SO questions, but none of them seems to be able to solve my problem. Sometimes I need to update one of the field from one participant, I want to update it in a way that when
//this data to apply update on the first element of the participants array
const partialParticipantUpdate = {
active: false
}
can be easily update to the sub document without rewriting all the other property. Basically like findByIdAndUpdate not findByIdAndReplace. I've tried aggregation but its only for reading data not writing data. I've also tried
let p = await Project.update({
"_id": mongoose.Types.ObjectId("5ee22f90e550c32194fb7a91"),
"participants._id": mongoose.Types.ObjectId("5ee4b5bd4fdcdb0c8813f5f5")
}, {
"$set": { "participants.0": partialParticipantUpdate } })
console.log(p);
However some of the participants property is removed after the update
{
"_id": { "$oid": "5ee22f90e550c32194fb7a91" },
"title": "Geo Chart Example",
"projectId": "myId",
"company": { "$oid": "5ee22ca46c7fc4358ced20a1" },
"description": "asd",
"remark": "re",
"active": true,
"participants": [{
"_id": { "$oid": "5ee4f37f4d8c234cc02d405a" },
"active": false,
"timeSpent": []
},
{
"_id": { "$oid": "5ee4c8a955ed7f23445a3cbc" },
"user": { "$oid": "5ee0bdc318998236706b5e5a" },
"active": true,
"timeSpent": []
}
],
"__v": 0
}
The update did change the first participant's "active" property from true to false, but it also lost some of the property like "user" and "timeSpent" array will get emptied as well
Finally I found the solution
const partialParticipantUpdate = {
active: false
}
let p = await Project.findById("5ee22f90e550c32194fb7a91");
let x = p.participants.id("5ee7224be4e4386084b87d3c");
x.set(partialParticipantUpdate);
let response = await p.save({ validateBeforeSave: false });
console.log(response);
The only downside is that I have to communicate with mongoose twice

How to select all the experiences from a specific user profile in Node and Mongoose from embedded schema

I'm building an API in NodeJS Express and MongoDB using Mongoose.
I created a Profile model that embeds the Experience schema.
Like:
{
"_id": "5e26ff6d5be84a3aeeb2f7bb",
"username": "some"
<fields of the profile>
"experience": [
{
"image": "",
"createdAt": "2020-01-21T13:41:01.873Z",
"updatedAt": "2020-01-21T13:41:01.873Z",
"_id": "5e26ff6d5be84a3aeeb2f7bc",
"title": "Senior Dev",
"role": "Dev",
"company": "ArosaDev",
"startDate": "2018-12-03T23:00:00.000Z",
"endDate": null,
"description": "",
"area": ""
}
],
"createdAt": "2020-01-21T13:41:01.874Z",
"updatedAt": "2020-01-21T13:41:01.874Z",
"__v": 0
}
The problem is I have to create an endpoint GET which gets for one profile all the experiences.
experienceRouter.get("/:username", async(req, res) => {
console.log(req.params.username);
const experiences = await Profiles.findOne({"username":req.params.username} ??? );
res.send(experiences);
});
I know I should select the embedded field experience and get back all the experiences but I don't know how should I do with Mongoose in my route.
I don't know what comes next after I select the username and how I can select the all experience for the username I'm requested.
I'm new to this and cannot find any good references explaining to me that for good.
I will appreciate an example of how a route like this should be done.
My model:
// Profile Schema model
// Embedded we have the Experience as []
const mongoose = require("mongoose");
const { isEmail } = require("validator");
const experienceSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
role: {
type: String,
required: true
},
company: {
type: String,
required: true
},
startDate: {
type: Date,
required: true
},
endDate: {
type: Date
},
description: {
type: String
},
area: {
type: String
},
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
},
image: {
type: String,
required: false,
default: "https://via.placeholder.com/150"
}
})
const profileSchema = new mongoose.Schema({
firstname: {
type: String,
required: true
},
surname: {
type: String,
required: true
},
email: {
type: String,
trim: true,
lowercase: true,
unique: true,
required: true,
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
],
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
}
});
const collectionName = "profiles";
const Profile = mongoose.model(collectionName, profileSchema);
module.exports = Profile;
replace your code with below
You can mention your fields which you need in the second argument of function this is called projection as mentioned
So for including of fields use 1 and for excluding fields use 0
experienceRouter.get("/:username", async(req, res) => {
console.log(req.params.username);
const profile = await Profiles.findOne({"username":req.params.username},{experience:1 ,username:1, _id:0}).lean();
res.send(profile);
});

Sending JSON obj fields in Insomnia

I'm trying to send a JSON object inside one of the fields I have, in order to store it in the MongoDB (Using Mongoose Schema). Right now I'm facing a server-sided JSON parsing error.
This is what I'm trying to send
{
"text":"N1y",
"localId":"123",
"type": "media",
"attachments": {
url:"Test.jpg",
publicId:"123"
}
}
My Moongose Schema
const messageSchema = mongoose.Schema({
createdAt: {
type: String,
default: new Date()
},
chatId: {
type: String,
required: true
},
localId: {
type: String,
required: true
},
text: {
type: String,
required: true
},
authorId: {
type: String,
required: true
},
type: {
type: String,
default: 'text'
},
attachments: {},
style: {
type: String,
default: 'normal'
}
Using Node.JS with Express.
In the schema update attachments type to object and request object in not correct json.
{
"text": "N1y",
"localId": "123",
"type": "media",
"attachments": {
"url": "Test.jpg",
"publicId": "123"
}
}
Schema
attachments: {
type : Object
},
OR
attachments: {
url: {
type: String
},
publicId: {
type: String
},
}

Resources