Multiple records for nested/embedded schema is not getting inserted in mongodb, nodejs - node.js

Hi I am new to nodejs and mongodb, I have json file with below structure,
I have defined one shipment schema with the "comments" section as nested schema
{
"buyerId": "B58",
"sellerId": "SL8",
"comments": {
"title": "title5",
"body": "body5",
"date": "12-07-2017"
}
}
I have defined one function like below
exports.post = function(req, res) {
const comments = []
var s = new shipment();
s.sellerId = req.body.sellerId;
s.buyerId = req.body.buyerId;
s.poId = req.body.poId;
s.comments.push({
title: req.body.comments.title,
body: req.body.comments.body,
date: req.body.comments.date
});
s.save(function(err) {
if (err) {
res.send(err);
}
console.log("added");
res.send({
message: 'shipment Created !'
})
})
}
The above 'post' function will work properly when I have only one "comments" section, I mean the data gets properly
inserted into the mongodb as shown below
{
"_id": ObjectId("59689bc59058dbc812000002"),
"buyerId": "B58",
"sellerId": "SL8",
"comments": [{
"title": "title5",
"body": "body5",
"date": ISODate("2017-12-06T18:30:00Z"),
"_id": ObjectId("59689bc59058dbc812000003")
}],
"__v": 0
}
but when I have multiple "comments" section as shown below,
{
"buyerId": "B58",
"sellerId": "SL8",
"comments": [{
"title": "title5",
"body": "body5",
"date": "12-07-2017"
},
{
"title": "title8",
"body": "body7",
"date": "12-07-2017"
}
]
}
then no comments section gets inserted into the mongodb as shown below.
{
"_id": ObjectId("5968c04d4c02336800000002"),
"buyerId": "B57",
"sellerId": "SL7",
"comments": [{
"_id": ObjectId("5968c04d4c02336800000003")
}],
"__v": 0
}
what changes should I do in the function to get all the comments section being inserted into the mongodb properly ?

Instead of assigning value of every property, make instance and pass body directly into it.
const s = new shipment(req.body)
And then when you send data to the request, send in the following format
{ "buyerId": "B58", "sellerId": "SL8", "comments": [{ "title": "title5", "body": "body5", "date": "12-07-2017" }, { "title": "title8", "body": "body7", "date": "12-07-2017" } ] }

I tried like below and it worked.
for( var i = 0; i < req.body.comments.length; i++){
s.comments.push(
{ title: req.body.comments[i].title,
body : req.body.comments[i].body,
date : req.body.comments[i].date });
}

originally comments is an array in the second example comments is an array.
your function
s.comments.push({
title: req.body.comments.title,
body: req.body.comments.body,
date: req.body.comments.date
})
will only work if comments is an object. Put that in a for loop to make it work with arrays like so
for( var i = 0; i < req.body.comments.length; i++){
s.comments.push({
title: req.body.comments[i].title,
body: req.body.comments[i].body,
date: req.body.comments[i].date
})
}

Related

MongoDb find all objects that contain nested value

This is my user object sent as token in req:
{
"_id": "6212aba16653621e67393549c",
"name": "User",
"email": "user#gmail.com",
"__v": 0
}
This is my get function code:
const getSharedLists = asyncHandler(async (req, res) => {
const lists = await List.find({
sharedWith: { email: req.user.email },
});
res.status(200).json(lists);
});
This is what object looks like:
{
"_id": "621817233300dfff68e23710",
"user": "6212ab33383621e67393549c",
"listName": "test update",
"private": true,
"items": [
{
"itemName": "Bananas",
"quantity": 3,
"isBought": false,
"isle": "isle",
"_id": "621b043622147906eece2e72"
},
],
"sharedWith": [
{
"email": "user#gmail.com",
"_id": "621bdbf0791a322534284c49"
}
],
"createdAt": "2022-02-24T23:39:25.668Z",
"updatedAt": "2022-02-27T21:21:03.584Z",
"__v": 0,
},
I keep getting empty array back, even when hard code req.user.email as "user#gmail.com" for example. I need to find all lists on MongoDb that have my email in array of sharedWith.
Can somebody help please. Apparently I'm using List.find method wrong but can't seem to figure out the syntax.
You need (.) dot notation.
const lists = await List.find({
"sharedWith.email" : req.user.email
});
Sample Mongo Playground
Reference
Specify a Query Condition on a Field Embedded in an Array of Documents

How to filter mongoDB in NodeJS API, checking if values are included in objects in array

I am writing REST API in NodeJS with MongoDB. Structure of the database is:
[
{
"_id": "12345",
"name": "Meal name",
"category": "dessert",
"area": "british",
"imageUrl": "https.image.jpg",
"instructions": "some instructions...",
"ingredients": [
{
"name": "salt",
"measure": "1g"
},
{
"name": "chicken",
"measure": "1"
},
{
"name": "butter",
"measure": "90g"
}, ...
]
}, ...
]
I can write a route to get data which meet one condition,
i.e.:
//getting all, when category = :category
router.get('/meals/category=:category', async (req, res) => {
try {
const meals = await Meal.find({category: req.params.category})
res.json(meals)
} catch (err) {
res.status(500).json({ message: err.message })
}
})
Here, route
'meals/category=vegetarian'
get all data with category = vegetarian.
However, I want to have route, which will filter all data by parameters: category, area, ingredients.
For example:
meals/ingredients=salt,pepper&category=dessert&area=american
should return all data, which contains salt and pepper in array, and category = dessert.
another example:
meals/area=american&category=dessert
should return all data, where area=american and category=dessert
How can I write the router.get() method to achieve that?

Mongoose NodeJS Express - How to Push Data To a Specific Sub Document Object Array

thank you in advance for any help.
My problem is essentially to add data to a specific sub document.
I have the following models in my NodeJS server:
MODELS
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const dataSchema = new Schema({
time: Date,
value: String
});
const nodeSchema = new Schema({
name: String,
description: String,
number: Number,
status: String,
lastSeen: Date,
data: [dataSchema]
});
const siteSchema = new Schema({
code: String,
name: String,
description: String,
totalNodes: Number,
nodes: [nodeSchema]
});
const Site = mongoose.model('site',siteSchema);
module.exports = Site;
Which basically looks like this:
Example
{
"_id": "5fa169473a394829bc485069",
"code": "xfx3090",
"name": "Name of this site",
"description": "Some description",
"totalNodes": 2,
"__v": 0,
"nodes": [
{
"_id": "5fa1af361e085b516066d7e2",
"name": "device name",
"description": "device description",
"number": 1,
"status": "Offline",
"lastSeen": "2020-11-03T19:27:50.062Z",
"data": [
{
"Date": "2019-01-01T00:00:00.000Z",
"value": "12"
},
{
"Date": "2019-01-01T00:00:00.000Z",
"Value": "146"
}
]
},
{
"_id": "5fa1b10f4f24051520f85a58",
"name": "device name",
"description": "device description",
"number": 2,
"status": "Offline",
"lastSeen": "2020-11-03T19:35:43.409Z",
"data": [
{
"Date": "2019-01-01T00:00:00.000Z",
"Value": "555"
}
]
}
]
}
]
As you can see I have created two dummy nodes with some random data.
My question now is, say I want to add some data to Node 1. How will this code look?
I've tried many variations and attempted many different things without any luck. I know this would be easier by using the Object Id's, but I was hoping there is a way around this.
My Best result so far was with this code, but unfortunately it doesn't add any data.
addNodeData: async (req,res,next) => {
const {siteCode} = xfx3090; //req.params
const { nodeNumber } = 1; //req. params - just to show example
const nodeData = await Site.findOneAndUpdate({'code': siteCode, 'node.number': nodeNumber}, {$push: {'data':{'time': Date.now(), 'value':1223}}});
res.status(200).json({message:'success'});
}
Thank you in advance!
You need the positional operator $.
The query you want is something like this:
db.collection.update({
"_id": "5fa169473a394829bc485069",
"nodes._id": "5fa1af361e085b516066d7e2"
},
{
"$push": {
"nodes.$.data": {
"Date": "newDate",
"value": "newValue"
}
}
})
The first part is to find the document. I'm assuming nodes._id is not unique so I match _id too.
Then, with the pointer in the document you want to add the new data, you use $push into nodes.$.data. So, in the filed data there will be a new object.
A mongo plauground example is here

How to build a search endpoint in a API to find and filter results from a database

In my Node API and MongoDB, I'm trying to build an endpoint to search for data in the DB and get back the results to the client. My search goal is to show results from the Profile collection and in that way, I can build my queries to search by first name, surname, company and the combination of it as an example:
GET search?fn=joe or ?ln=doe or ?cp=Company or ?fn=...&ln=...&cp=...
Practically I can search in different ways and I can get for example all the people working for a company as a result of a search.
I would like to understand how can I achieve that with Mongoose/MongoDB and add also to the query optional a limit/pagination for the coming results.
I tried to make some simple trials but I got stuck as I do not really get it how to proceed next.
const SearchController = {
async getQuery(req, res) {
try {
const { fn, ln, cp } = req.query;
const searchResult = await Profile.find({
$or: [
{ firstname: fn },
{ surname: ln },
{
experience: {
company: cp
}
}
]
});
res.status(200).json(searchResult);
} catch (err) {
res.status(500).json({ message: err.message });
}
}
};
The JSON of a profile:
{
"imageUrl": "https://i.pravatar.cc/300",
"posts": [
"5e3cacb751f4675e099cd043",
"5e3cacbf51f4675e099cd045",
"5e3cacc551f4675e099cd046"
],
"_id": "5e2c98fc3d785252ce5b5693",
"firstname": "Jakos",
"surname": "Lemi",
"email": "lemi#email.com",
"bio": "My bio bio",
"title": "Senior IT developer",
"area": "Copenhagen",
"username": "Jakos",
"experience": [
{
"image": "https://via.placeholder.com/150",
"createdAt": "2020-02-04T13:47:37.167Z",
"updatedAt": "2020-02-04T13:47:37.167Z",
"_id": "5e3975f95fbeec9095ff3d2f",
"role": "Developer",
"company": "Google",
"startDate": "2018-11-09T23:00:00.000Z",
"endDate": "2019-01-05T23:00:00.000Z",
"area": "Copenhagen"
},
{
"image": "https://via.placeholder.com/150",
"createdAt": "2020-02-04T13:59:27.412Z",
"updatedAt": "2020-02-04T13:59:27.412Z",
"_id": "5e3978bf5e399698e20c56d4",
"role": "Developer",
"company": "IBM",
"startDate": "2018-11-09T23:00:00.000Z",
"endDate": "2019-01-05T23:00:00.000Z",
"area": "Copenhagen"
},
{
"image": "https://via.placeholder.com/150",
"createdAt": "2020-02-07T16:35:43.754Z",
"updatedAt": "2020-02-07T16:35:43.754Z",
"_id": "5e3d91dfb3a7610ec6ad8ee3",
"role": "Developer",
"company": "IBM",
"startDate": "2018-11-10T00:00:00.000Z",
"endDate": "2019-01-06T00:00:00.000Z",
"area": "Copenhagen"
}
],
"createdAt": "2020-01-25T19:37:32.727Z",
"updatedAt": "2020-02-04T23:14:37.122Z",
"__v": 0
}
The expected results are for example if I search the first name Joe I should get back all the profiles having as first name Joe. Similar for surname and company.
Please provide comments to allow me to understand if you need more scripts from the original code to see.
EDITED added the code modified of the search
// Models
const { Profile } = require("../models");
// Error handling
const { ErrorHandlers } = require("../utilities");
const SearchController = {
async getQuery(req, res) {
try {
const { fn, ln, cp } = req.query;
const query = {
$or: []
};
if (fn) query.$or.push({ firstname: fn });
if (ln) query.$or.push({ surname: ln });
if (cp) query.$or.push({ "experience.company": cp });
const searchResult = Profile.find(query, docs => {
return docs
});
if ((await searchResult).length === 0)
throw new ErrorHandlers.ErrorHandler(
404,
"Query do not provided any result"
);
res.status(200).json(searchResult);
} catch (err) {
res.status(500).json({ message: err.message });
}
}
};
module.exports = SearchController;
Have tried conditional query and modified your array search query for finding the company,
function findUser(fn, ln, cp) {
const query = {
$or: []
}
if (fn) query.$or.push({ firstname: fn })
if (ln) query.$or.push({ surname: ln })
if (cp) query.$or.push({ "experience.company": cp })
Profile.find(query, function (err, docs) {
if (err) {
console.error(err);
} else {
console.log(docs);
}
});
}
findUser("","","IBM")

Mongoose: Update does not work in nested array object

I have a document with the array of objects and one object contains multiple objects I want to update inner object with $set but didn't get any luck.
can anybody give me any hint so that I can resolve it?.
This is my object:
{
"_id": ObjectId("56fbfafdf86fa6161911d104"),
"site": "xyz",
"adsPerCategory": NumberInt(2),
"sampledAt": ISODate("2016-03-30T16:12:45.138+0000"),
"items": [
{
"id": "4563873",
"content": {
"title": "WATER DISTILLERS",
"body": "Perfect to save money.",
}
},
{
"id": "4563s23232873",
"content": {
"title": "Cola water",
"body": "Perfect for body.",
}
}
]
}
I want to update body.
for now, I have given single object but it can be multiple.
Here what I tried
models.Sample.update(
{
_id: samples._id
},
'$set': {
'items.0.content.body': body.description
},
function(err, numAffected) {
console.log(err);
console.log('Affected....', numAffected);
}
);
It's working fine if I put 0 but I want to make it dynamic.
Like 'items.index.content.body': body.description
Thank You.
I think you can do something like this.
models.Sample.find({ _id: ObjectId(samples._id) })
.forEach(function (doc) {
doc.items.forEach(function (element, index, array) {
items[index].content.body = body.description;
});
models.Sample.save(doc);
});

Resources