My Schema be like as follows
var DeptSchema = new Schema({
name : {type : String, default: ''},
sku : {type : String, default: ''}, // (SKU = stock keeping unit)
Product : {
name : {type : String, default: '', unique:true},
sku : {type : String, default: '', unique:true}, // (SKU = stock keeping unit)
description : {type : String, default: '100gm'},
price : {type : String, default: ''},
quantity : {type : Number, default: '0'},
isFav : {type : Boolean, default: 'false'}
}
});
Via Mongoose I've Created an API, but PROBLEM starts when I want to add Products to a specific Dept(Department), A whole new Instance of Department is created instead of the new Product getting appended to the existing Department.
My POST/PUT stated below is
.put(function(req, res) {
// use our Dept model to find the Dept we want
Dept.findById(req.params.Dept_id, function(err, Dept) {
if (err)
res.send(err);
Dept.name = req.body.name; // update the Dept info
Dept.sku = req.body.sku;
Dept.Product.name = req.body.ProductName;
Dept.Product.sku = req.body.ProductSKU;
Dept.Product.description = req.body.ProductDescription;
Dept.Product.price = req.body.ProductPrice;
Dept.Product.quantity = req.body.ProductQuantity;
Dept.Product.isFav = req.body.ProductisFav;
// save the Dept
Dept.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Department updated!' });
});
});
})
.post(function(req, res) {
var dept = new Dept(); // create a new instance of the Dept model
dept.name = req.body.name; // set the Dept name (comes from the request)
dept.sku = req.body.sku;
dept.Product.name = req.body.ProductName;
dept.Product.sku = req.body.ProductSKU;
dept.Product.description = req.body.ProductDescription;
dept.Product.price = req.body.ProductPrice;
dept.Product.quality = req.body.ProductQuality;
dept.Product.isFav = req.body.ProductisFav;
// save the Dept and check for errors
dept.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Department created!' });
});
})
e.g. We can easily see from the output that Different Fruits instead of appending to the same Fruits Dept. are creating a whole another instance. Also why does ProductSchema not have auto generated Object Id?
[
{
"__v": 0,
"_id": "5528027cd4eb13d80cf81f87",
"Product":
{
"isFav": true,
"quantity": 34,
"price": "128",
"description": "1kg",
"sku": "APL",
"name": "Apple"
},
"sku": "FRT",
"name": "Fruits"
},
{
"_id": "552824abd67bf9d81391ad92",
"__v": 0,
"Product":
{
"isFav": true,
"quantity": 0,
"price": "40",
"description": "1kg",
"sku": "ORG",
"name": "Orange"
},
"sku": "FRT",
"name": "Fruits"
}
]
Thank You for being Patient.
You have declared Product to be an object and not an array.
Product: {...} --> Product: [{...}]
Also you would need to update your put method to push a new item onto the Dept.Product array rather than updating the properties of Dept. You can read how to properly use subdocs in the documentation.
Related
thanks for click my question..
I have two schemas in mongodb, citySchema and destinationSchema. I want to make one to many relation. Each destination has one city and the city has many destinations.
This is my destinationSchema
var mongoose = require("mongoose");
var destinationSchema = new mongoose.Schema({
name: String,
image: String,
description: String,
city: {
type: mongoose.Schema.Types.ObjectId,
ref: "City"
}
});
module.exports = mongoose.model("Destination", destinationSchema);
This is citySchema
var mongoose = require("mongoose");
var citySchema = new mongoose.Schema({
name: String,
image: String,
description: String,
destinations: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Destination"
}
]
});
module.exports = mongoose.model("City", citySchema);
And this is the post route to create new destination
router.post("/", function(req, res) {
var name = req.body.name;
var image = req.body.image;
var description = req.body.description;
var city = req.body.city;
var newDestination = {
name: name,
image: image,
description: description,
city: city
};
Destination.create(newDestination, function(err, newCreatedDestination) {
if (err) {
console.log(err);
} else {
res.redirect("/admin/destinations");
}
});
});
This is my form to create a new destination
<select name="city">
<% cities.forEach(function(city) { %>
<option value=<%=city._id%> > <%= city.name %> </option>
<% }) %>
</select>
It works fine. But I want when i create a new destination, it push current destination id to city schema (destinations array).
Sorry for my bad English. I appreciate every your answers and suggestions. And Thank you 😊
After you create a new destination, you can push that destination's id to the city destinations.
You can use the following route:
router.post("/", async (req, res) => {
try {
const { name, image, description, city } = req.body;
let newDestination = { name, image, description, city };
newDestination = await Destination.create(newDestination);
let result = await City.findByIdAndUpdate(
city,
{
$push: { destinations: newDestination._id }
},
{ new: true }
);
res.redirect("/admin/destinations");
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});
Let's have an existing city like this:
{
"destinations": [],
"_id": "5e071f212e9ecd31508785c6",
"name": "Padang",
"image": "image 1",
"description": "beautiful city",
"__v": 0
}
If we want to add this city a destination, we can send this request body to our post route. Please note that as city value, we need to use an existing city id (5e071f212e9ecd31508785c6) like the one we have already.
{
"name": "destination name",
"image": "destination image",
"description": "destination description",
"city": "5e071f212e9ecd31508785c6"
}
The result will be like this:
A new destionation is created:
{
"_id" : ObjectId("5e071fd51cd3600bb083b5e7"),
"name" : "destination name",
"image" : "destination image",
"description" : "destination description",
"city" : ObjectId("5e071f212e9ecd31508785c6"),
"__v" : NumberInt(0)
}
And added to the city:
{
"_id" : ObjectId("5e071f212e9ecd31508785c6"),
"destinations" : [
ObjectId("5e071fd51cd3600bb083b5e7")
],
"name" : "Padang",
"image" : "image 1",
"description" : "beautiful city",
"__v" : NumberInt(0)
}
After creating a destination, use mongoose findOneAndUpdate method to update the relevant city.
As the name implies, findOneAndUpdate() finds the first document that
matches a given filter, applies an update, and returns the document.
Mongoose findOneAndUpdate
I have an almost working solution, but I believe my solution is bad programmed and I don't know how to make it better. Maybe it should be done with mongoose population, but I can't figure out how it works and how to adjust my code.
I have 2 collections: author and books. They are imported from MySQL with data - so I can't change the structure.
author:
{ "_id" : ObjectId("59492addd80eb0f9c1b42fd9"), "id_a" : 1, "name" : "Agatha Christie", "gender" : "female", "born" : 1890, "birthplace" : "England", "genre" : "crime"
}
{ "_id" : ObjectId("594935e1d80eb0f9c1b42fdb"), "id_a" : 2, "name" : "Stephen King", "gender" : "male", "born" : 1947, "birthplace" : "U.S.", "genre" : "horror" }
books:
{ "_id" : ObjectId("59492cd1d80eb0f9c1b42fda"), "id_b" : 1, "title" : "Murder on the Orient Express", "id_a" : 1, "pub_date" : 1934, "publisher" : "Collins Crime Club",
"pages" : 256, "description" : "Hercule Poirot, the internationally famous detective, boards the Orient Express (Simplon-Orient-Express) in Istanbul. The train is unus
ually crowded for the time of year. Poirot secures a berth only with the help of his friend Monsieur Bouc, a director of the Compagnie Internationale des Wagons-Lits. W
hen a Mr. Harris fails to show up, Poirot takes his place. On the second night, Poirot gets a compartment to himself..." }
{ "_id" : ObjectId("59493779d80eb0f9c1b42fdc"), "id_b" : 2, "title" : "The A.B.C. Murders", "id_a" : 1, "pub_date" : 1936, "publisher" : "Collins Crime Club", "pages" :
256, "description" : "The novel follows the eponymous murders and their investigation as seen by Arthur Hastings, Poirot's old friend. Poirot receives typed letters si
gned by A.B.C. In each is given the date and location of the next murder. A.B.C. moves alphabetically: Alice Ascher is a tobacco shop owner killed in her shop in Andove
r, Betty Barnard is a flirty waitress killed in Bexhill, and Sir Carmichael Clarke is a wealthy man killed at his home in Churston..." }
{ "_id" : ObjectId("59493858d80eb0f9c1b42fdd"), "id_b" : 3, "title" : "The Shining", "id_a" : 2, "pub_date" : 1977, "publisher" : "Doubleday", "pages" : 447, "descripti
on" : "The Shining mainly takes place in the fictional Overlook Hotel, an isolated, haunted resort located in the Colorado Rockies. The history of the hotel, which is d
escribed in backstory by several characters, includes the deaths of some of its guests and of former winter caretaker Delbert Grady, who succumbed to cabin fever and ki
lled his family and himself..." }
I want to find with author's name his id in the collection author and use his id to find all his books in the collection books. But the json-result should be a combination of selected field from both collections. For example I search for Agatha Christie and want get following selected fields as one json-object (name and genger from author + title and description from books as one object) Desired Api result in postman:
[ {
"name": "Agatha Christie",
"gender": "femail",
"title" : "Murder on the Orient Express",
"description" : "Hercule Poirot, the internationally famous detective, boards the Orient Express (Simplon-Orient-Express) in Istanbul...."
},
{
"name": "Agatha Christie",
"gender": "femail",
"title" : "The A.B.C. Murders",
"description" : "The novel follows the eponymous murders and their investigation as seen by Arthur Hastings, Poirot's old friend..."
}]
here is my code:
api.js
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
mongoose.connect('mongodb://localhost/books');
var db = mongoose.connection;
db.on('connected', function() {
console.log('MongoDB connection successful');
});
Author = require('./models/books');
Book = require('./models/books');
app.post('/api/Books', function(req, res){
Author.getAuthor({name : req.body.name}, 10, function(err, data){
if (err){
throw err;
}
var tmp = data[0].id_a;
Book.getBook({id_a : tmp}, 10, function(err, data2){
if (err){
throw err;
}
var result = [data, data2];
console.log(result);
res.json(result);
});
});
});
app.listen(3000);
console.log('server started and waits on port 3000');
books.js
var mongoose = require('mongoose');
var authorSchema = mongoose.Schema({
id_a:{
type: Number,
required: true
},
name:{
type: String,
required: true
},
gender:{
type: String,
required: true
},
born:{
type: Number,
required: true
},
birthplace:{
type: String,
required: true
},
genre:{
type: String,
required: true
}},
{ collection: 'author'}
);
var booksSchema = mongoose.Schema({
id_b:{
type: Number,
required: true
},
title:{
type: String,
required: true
},
id_a:{
type: Number,
required: true
},
pub_date:{
type: Number,
required: true
},
publisher:{
type: String,
required: true
},
pages:{
type: Number,
required: true
},
description:{
type: String,
required: true
}},
{ collection: 'books'}
);
var Author = module.exports = mongoose.model('author', authorSchema);
var Book = module.exports = mongoose.model('books', booksSchema);
module.exports.getAuthor = function(query, limit, callback){
Author.find(query, {'_id': 0}).select('id_a').limit(limit).exec(callback);
}
module.exports.getBook = function(query, limit, callback){
Book.find(query).select('-_id id_a title').limit(limit).exec(callback);
}
With my app I can find the proper books to particular author, but my result is without author's name and gender - I don't know how to do it. Also I make a request with nested functions - there might be much better solution for it. My solution feels very dirty. How can I improve my code and get data from both collections? A working adjusted example would be realy great!
First you have to add those changes:
model:
var booksSchema = mongoose.Schema({
...
},
{ collection: 'books', toJSON: { virtuals: true } })
// Foreign keys definitions
// http://mongoosejs.com/docs/populate.html#populate-virtuals
booksSchema.virtual('author', {
ref: 'author',
localField: 'id_a',
foreignField: 'id_a',
justOne: true // for many-to-1 relationships
});
module.exports.getAuthor = function (query) {
return Author.findOne(query).exec();
}
// this help you get books with author
module.exports.getBook = function (query) {
return Book.find(query)
.populate('author')
.exec();
}
app code:
app.post('/api/Books', function (req, res) {
Author.getAuthor({ name: req.body.name }, 10)
.then(author => {
return Book.getBook({ id_a: author.id_a });
})
.then(result => {
console.log(result);
res.json(result);
})
.catch(error => {
// TODO:
});
});
result should be:
[{...book info,...author info }]
I hope this help you
I have a Model wich contains an array of sub-documents. This is a Company:
{
"_id" : ObjectId(":58be7c236dcb5f2feff91ac0"),
"name" : "sky srl",
"contacts" : [
{
"_id" : ObjectId("58be7c236dcb5f2feff91ac2"),
"name": { type: String, required: true },
"company" : ObjectId("58be7c236dcb5f2feff91ac0"),
"email" : "sky#gmail.com",
"chatId" : "",
"phone" : "123456789",
"name" : "John Smith"
},
{
"_id" : ObjectId("58be7f3a6dcb5f2feff91ad3"),
"company" : ObjectId("58be7f3a6dcb5f2feff91ad1"),
"email" : "beta#gmail.com",
"chatId" : "",
"phone" : "987654321",
"name" : "Bill Gaset"
}
],
"__v" : 1
}
I have several companies, and I want to update the field chatId of all the contacts in all the companies, that matches the phone I am searching for.
My Schema definitions (simplified, for focusing on question):
var contactSchema = new Schema({
[...]
phone: { type: String, required: true },
email: { type: String },
chatId: { type: String },
company: Schema.Types.ObjectId,
});
var companySchema = new Schema({
name: { type: String, required: true },
type: { type: String, default: "company" },
contacts: [contactSchema]
});
I tried
var conditions = { "contacts.phone": req.body.phone };
var partialUpdate = req.body; //it contains 'req.body.phone' and 'req.body.chatId' attributes
Company.find(conditions).then(
function (results) {
results.map( function(companyFound) {
companyFound.contacts.forEach(function (contactContainer){
if (contactContainer.phone == partialUpdate.phone) {
contactContainer.chatId = partialUpdate.chatId;
Company.save();
companyFound.save();
contactContainer.save();
results.save();
}
//not sure of what to save, so i save everything
companyFound.save();
contactContainer.save();
results.save();
});
});
});
following this answer; but it doesn't works. It does not save anything, what I'm doing wrong?
I have never done this before, but worth a try.
Maybe you need to use $elemMatch.
// find the companies that have contacts having the phone number
Company.find().where('contacts', { $elemMatch: { phone: req.body.phone }}).exec(function (err, companies) {
if (err) {
console.log(err);
return;
}
// see if you can at least get the query to work
console.log(companies);
async.eachSeries(companies, function updateCompany(company, done) {
// find and update the contacts having the phone number
company.contacts.forEach(function (contact, i, arr) {
if (contact.phone == req.body.phone) {
arr[i].chatId = req.body.chatId;
}
});
company.save(done);
}, function allDone (err) {
console.log(err);
});
});
Note, I am using async.js to do async operations on multiple items.
Honestly, I would have simply made contacts an array of Contact references -- much easier to query and update.
Just for the records: I did this to make it work without async.js:
Company.find().where('contacts', { $elemMatch: { phone: req.body.phone } })
.exec(function (err, companies) {
if (err) {
console.log(err);
return;
}
console.log("companies: " + JSON.stringify(companies, null, 4));
companies.forEach(function (company) {
company.contacts.map(function (contact, i, arr) {
if (contact.phone == req.body.phone) {
arr[i].telegramChatId = req.body.telegramChatId;
}
});
company.save();
},
function allDone(err) {
console.log(err);
});
});`
I'm trying to connect 3 different documents using mongoose (mainly to learn how to use it), I've set up 3 different schemas as follows:
(all of them are in there own files)
const Books = new Schema({
title: { type: String, required: true, unique: true },
description: String,
author: { type: mongoose.Schema.Types.ObjectId, ref: 'Authors' },
stores: [{
available: Number,
store: { type: mongoose.Schema.Types.ObjectId, ref: 'Stores' }
}]
});
exports.Books = mongoose.model('Books', Books);
const Authors = new Schema({
name: { type: String, required: true },
description: String,
born: Date,
died: { type: Date, default: null }
});
exports.Authors = mongoose.model('Authors', Authors);
const Stores = new Schema({
name: { type: String, required: true, unique: true },
description: String,
address: String
});
exports.Stores = mongoose.model('Stores', Stores);
and then I add the following data:
author.name = 'Jonathan Swift';
author.description = 'old satiric bloke';
author.born = new Date(1667, 10, 30);
author.died = new Date(1745, 9, 19);
author.save()
.catch((err) => console.log(err))
.then(() => console.log('author saved'));
store.name = 'Book shop 1';
store.description = 'This is where the cool kids buy all there books!';
store.address = 'La La Land, 123 Combaja street';
store.save()
.catch((err) => console.log(err))
.then(() => console.log('store saved'));
book.title = 'gullivers travels';
book.author = '58a79345711f2350999e0911'; // _id from the author save
book.description = 'A book about a big guy in a small world';
book.stores = [{
available: 8,
store: '58a79345711f2350999e0912' // _id from the store save
}];
book.save()
.catch((err) => console.log(err))
.then(() => console.log('store saved'));
The problem I find is that when I run book.find() it returns:
[
{
"_id": "58a795b8298b50527412815c",
"description": "A book about a big guy in a small world",
"author": {
"_id" : "58a79345711f2350999e0911",
"born" : -9532947600000,
"died" : -7075130400000,
"description" : "old satiric bloke",
"name" : "Jonathan Swift",
"__v" : 0
},
"title": "gullivers travels",
"__v": 0,
"stores": [
{
"available": 8,
"store": "58a79345711f2350999e0912",
"_id": "58a795b8298b50527412815d"
}
]
}
]
what I was expecting/hoping for was to get the entire store as well the same way as with the author, have I missed something or how should I go about this to achieve the expected result?
I've tried populate but without success
In your Books model author & stores.store are reference, you shouldn't have author field populated if you don't use populate().
If you specify directly the _id of your store & author you have just created :
var author = new Authors({
name: 'Jonathan Swift',
description: 'old satiric bloke',
born: new Date(1667, 10, 30),
died: new Date(1745, 9, 19)
});
author.save();
var store = new Stores({
name: 'Book shop 1',
description: 'This is where the cool kids buy all there books!',
address: 'La La Land, 123 Combaja street'
});
store.save();
var book = new Books({
title: 'gullivers travels',
author: author._id, // _id from the author save
description: 'A book about a big guy in a small world',
stores: [{
available: 8,
store: store._id // _id from the store save
}]
})
book.save();
Books.find() gives the expected result :
[
{
"_id": "58a7a2529a8b894656a42e00",
"title": "gullivers travels",
"author": "58a7a2529a8b894656a42dfe",
"description": "A book about a big guy in a small world",
"__v": 0,
"stores": [
{
"available": 8,
"store": "58a7a2529a8b894656a42dff",
"_id": "58a7a2529a8b894656a42e01"
}
]
}
]
If you want stores.store & author populated, use :
Books.find().populate([{path:'author'},{path:'stores.store'}]).exec(function(err, res) {
console.log(JSON.stringify(res, null, 2));
});
It gives as expected author & stores.store both populated :
[
{
"_id": "58a7a2529a8b894656a42e00",
"title": "gullivers travels",
"author": {
"_id": "58a7a2529a8b894656a42dfe",
"name": "Jonathan Swift",
"description": "old satiric bloke",
"born": "1667-11-29T23:00:00.000Z",
"__v": 0,
"died": "1745-10-18T22:00:00.000Z"
},
"description": "A book about a big guy in a small world",
"__v": 0,
"stores": [
{
"available": 8,
"store": {
"_id": "58a7a2529a8b894656a42dff",
"name": "Book shop 1",
"description": "This is where the cool kids buy all there books!",
"address": "La La Land, 123 Combaja street",
"__v": 0
},
"_id": "58a7a2529a8b894656a42e01"
}
]
}
]
For mongodb's embedded document, I don't know why the data is not saved in the database or something else might be wrong? I tried to print out everything to make sure it works till the last step. But still got nothing when querying the embedded document, as you can see from below.
My schema:
// create competitorAnalysisSchema
var CompetitorAnalysis = new Schema({
firstObservation: { type: String },
secondObservation: { type: String },
thirdObservation: { type: String },
brandName: { type: String },
productCategory: { type: String },
photo1: { data: Buffer, contentType: String },
photo2: { data: Buffer, contentType: String },
photo3: { data: Buffer, contentType: String },
photo4: { data: Buffer, contentType: String }
});
// create UserSchema
var UserSchema = new Schema({
userName: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
currentDemo: { type: String },
nextDemo: { type: String },
startTime: { type: String },
startLocation: { type: String },
arriveTime: { type: String },
arriveLocation: { type: String },
leaveTime: { type: String },
leaveLocation: { type: String },
competitorAnalysis: [CompetitorAnalysis],
created_at: Date,
updated_at: Date
});
var User = mongoose.model('User', UserSchema);
module.exports = User;
In my index.js, all debug messages can be successfully printed out.:
// on routes that end in /users/competitorAnalysisTextData
// ----------------------------------------------------
router.route('/users/competitorAnalysisTextData/:userName')
// update the user info (accessed at PUT http://localhost:8080/api/users/competitorAnalysisTextData)
.put(function(req, res) {
// use our user model to find the user we want
User.findOne({ userName: req.params.userName}, function(err, user) {
if (err)
res.send(err);
console.log('Got the user!');
// update the text data
user.competitorAnalysis.firstObservation = req.body.firstObservation;
user.competitorAnalysis.secondObservation = req.body.secondObservation;
user.competitorAnalysis.thirdObservation = req.body.thirdObservation;
user.competitorAnalysis.brandName = req.body.brandName;
user.competitorAnalysis.productCategory = req.body.productCategory;
console.log('req.body.firstObservation: %s', req.body.firstObservation);
console.log('user.competitorAnalysis.firstObservation: %s', user.competitorAnalysis.firstObservation);
console.log('Save the text data for competitorAnalysisTextData!');
// save the user
user.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'User updated!' });
console.log('user.competitorAnalysis.firstObservation: %s', user.competitorAnalysis.firstObservation);
console.log('Finally save the User!');
});
});
})
As in console:
Got the user in "Put"!
req.body.firstObservation: 3
user.competitorAnalysis.firstObservation: 3
Save the text data for competitorAnalysisTextData!
user.competitorAnalysis.firstObservation: 3
Finally save the User!
Problem
However, when I search in my mongodb database, there is no data saved for the embedded document:
...
"leaveTime" : "Your Current Time:\n 2016-08-23 10:27:45 AM",
"leaveLocation" : "Your Current Address:\n 1\nInfinite Loop\nCupertino\n95014",
"competitorAnalysis" : [ ]
}
> db.users.find({"competitorAnalysis.firstObservation" : "3"}).pretty()
>
Empty here!
I'm new to mongodb. It'll be great if I can get some hints on where else I can check or what the problem might be.
Update
Output of collection:
> db.users.find().pretty()
{
"_id" : ObjectId("57ba5f41ad8858305a5d3e58"),
"created_at" : ISODate("2016-08-22T02:11:13.968Z"),
"updated_at" : ISODate("2016-08-24T19:42:56.311Z"),
"nextDemo" : "12:00pm - 3:00pm, Whole Foods Market, 5880 Centre Ave, Pittsburgh PA 15206",
"currentDemo" : "9:00am - 1:00pm, Whole Foods Market, 5880 Centre Ave, Pittsburgh PA 15206",
"password" : "<3da4dafc c96e05cd 855da8b3 ff0bf074 8156ec4b b9f1a002 ba907bcc d5e4aa5b fcd2fef9 dec240cd 86489978 7d85cec8 f11eae1c 7b60b2cc 6693da1a 4eae3a73>",
"email" : "chenya#gmail.com",
"userName" : "Chenya",
"__v" : 1,
"startLocation" : "Your Current Address:\n 10141\nBilich Pl\nCupertino\n95014",
"startTime" : "Your Current Time:\n 2016-08-24 03:42:42 PM",
"arriveTime" : "Your Arriving Time:\n 2016-08-24 03:42:44 PM",
"arriveLocation" : "Your Arriving Address:\n 10131\nBilich Pl\nCupertino\n95014",
"leaveTime" : "Your Current Time:\n 2016-08-23 10:27:45 AM",
"leaveLocation" : "Your Current Address:\n 1\nInfinite Loop\nCupertino\n95014",
"competitorAnalysis" : [ ]
}
>
These statements are the problem:
user.competitorAnalysis.firstObservation = req.body.firstObservation;
user.competitorAnalysis.secondObservation = req.body.secondObservation;
user.competitorAnalysis.thirdObservation = req.body.thirdObservation;
user.competitorAnalysis.brandName = req.body.brandName;
user.competitorAnalysis.productCategory = req.body.productCategory;
You're treating your competitorAnalysis array as if it were an object.
I don't work with Mongoose, so don't know the syntax, but you want to do something like this instead:
user.competitorAnalysis.push({
firstObservation: req.body.firstObservation,
secondObservation: req.body.secondObservation,
thirdObservation: req.body.thirdObservation,
brandName: req.body.brandName
productCategory: req.body.productCategory
});