crud operation on nested array mongodb - node.js

[
"id": 1,
"name": "Afghanistan",
"iso3": "AFG",
"iso2": "AF",
"states": [
{
"id": 3901,
"name": "Badakhshan",
"state_code": "BDS",
"latitude": "36.73477250",
"longitude": "70.81199530",
"type": null,
"cities": [
{
"id": 52,
"name": "Ashkāsham",
"latitude": "36.68333000",
"longitude": "71.53333000"
},]
let filter = { iso2: country_code ,name:country_name,"states.state_code":state_code,"states.name":state_name };
let newvalues = { $push:
{"states.$[].cities": [{ name: state_name, code:city_code }]}}
dbo.collection("countries").updateOne(filter, newvalues,{upsert:true}, async function (err, result) {
if (err) {
res.json({success:false, response: err.message,statusbar:err})
}
res.json({success: true, statuscode: 200, response: result})
db.close();
Hi all I am trying to add,delete and update city which is as object inside a states array i tried as above did not workout need a suggestion tqq

Related

trying to update nested array in mongodb

` "id": 1,
"name": "Afghanistan",
"iso3": "AFG",
"iso2": "AF",
"states": [
{
"id": 3901,
"name": "Badakhshan",
"state_code": "BDS",
"latitude": "36.73477250",
"longitude": "70.81199530",
"type": null,
"cities": [
{
"id": 52,
"name": "Ashkāsham",
"latitude": "36.68333000",
"longitude": "71.53333000"
},
dbo.collection("countries").updateOne(myquery,
{ $set: { "states.$[].cities.$[filter].name": new_name } },
{ arrayFilters: [ {"filter.name":old_city_name} ] },
async function (err, result) {
if (err) {
return res.json({ success: false, response: err.message, statusbar: err })
}
res.json({ success: true, statuscode: 200, response: result });
db.close();
});
trying to update a city name which in the states array its working but its updating every city in that particular state need some help guys
tq all

Get aggregate with lookup in single Object

my problem is how I get a simple object of ownerDetails, correct me if my code is wrong
data I got, from my code
{
"status": true,
"data": [
{
"_id": "61a2a9680b122bc154cbd6af",
"ownerName": "Ajay",
"mobile": 878787878,
"designation": "IT",
"gender": "Male",
"age": 26,
"carDetails": [
{
"carName": "BUY",
"color": "blue",
"sheets": 8,
"avgSpeed": 105,
"price": 850000,
"model": "C110"
},
{
"carName": "GTR",
"color": "blue",
"sheets": 4,
"avgSpeed": 105,
"price": 98000,
"model": "G120"
}
]
}
]
}
i want data like this,
{
"status": true,
"ownerDetails": {
"_id": "61a2a9680b122bc154cbd6af",
"ownerName": "Ajay",
"mobile": 878787878,
"designation": "IT",
"gender": "Male",
"age": 26,
"total_car": 2,
}
}
code for getting data from collections
exports.getOwnerDetails = async (req, res, next) => {
try {
Owner.aggregate([
{
$match: { ownerName: req.body.ownerName }
},
{
$lookup: {
from: "cars",
localField: "ownerName",
foreignField: "ownerName",
as: "carDetails",
},
},
{
$project: {
"carDetails._id": 0,
"carDetails.ownerName": 0,
},
},
]).then((data) => {
res.json({
status: true,
data: data,
});
});
} catch (error) {
res.status(500).json({
status: false,
msg: "Error : " + error,
});
}
};
in may returning data, I got an array of carDetails, but I only need that how many are owned by an Owner, and return a simple object of ownerDetails
$lookup return an array because more than one values can match the join. If you want to get only one value you can get the first element from the array. Then you can add these aggregation stages:
First $addFields to get the first element from the array (index 0).
Then use $project to get the desired output.
{
"$addFields": {
"data": {
"$arrayElemAt": ["$data",0]
}
}
},
{
"$project": {
"status": 1,
"ownerDetails": {
"_id": "$data._id",
"ownerName": "$data.ownerName",
"mobile": "$data.mobile",
"designation": "$data.designation",
"gender": "$data.gender",
"age": "$data.age",
"total_car": {
"$size": "$data.carDetails"
}
}
}
}
Example here
Query
i am not sure if this is what you want
unwind all owners from data
and from each owner, count its cars number
Test code here
aggregate(
[{"$unwind": {"path": "$data"}},
{"$set":
{"data.total_car": {"$size": "$data.carDetails"},
"data.carDetails": "$$REMOVE",
"_id": "$$REMOVE"}},
{"$set": {"ownerDetails": "$data", "data": "$$REMOVE"}}])

Mongoose MongoDB updating a nested array

I have the following schema and I'm trying to update the heart_rates and glucose_levels arrays by adding a new entry:
"days": [
{
"day": "16-12-2020",
"data": {
"average_score": 80,
"metabolic_score": 80,
"cardio_score": 80,
"heart_rates": [{
"start_date": "timestamp",
"end_date": "timestamp",
"value": 100
}],
"glucose_levels": [{
"start_date": "timestamp",
"end_date": "timestamp",
"value": 100
}],
"weekly_health_recap": {
"id": "",
"start_date": "timestamp",
"end_date": "timestamp",
"rating": "Excellent"
},
"summaries": [{
"type": "meal",
"actions": [
"sweets", "fruits"
],
"title": "",
"start_date": "",
"end_date": ""
}],
"articles": [{
"id": "",
"name": "",
"text": "",
"image_url": ""
}]
}
}
]
I tried various solutions, however they didn't give the expected results.
Currently, I'm using the following code to find if there is an existing entry for the day, if there is not, I'm creating it using findByIdAndUpdate and upsert, if there is already a day entry then I'm using update and push to add a new entry in the heart_rates array. The problem is that the update inserts the new entry in some other day entry and not the one that I'm querying for.
exports.updateDayHeartrate = async (req, res) => {
User.find({ "_id": req.body._id, "days.day": req.body.day}, function (err, docs) {
if (err){
return done(err);
}
if (docs.length > 0) {
User.update({"_id": req.body._id, "days.day": req.body.day},
{$push: {"days.0.data.heart_rates": req.body.data}},
(err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
else if (user) {
res.status(200).send("Updated!")
}
}
)
}
else{
User.findByIdAndUpdate(req.body._id,
{$push: {"days": {"day": req.body.day, "data": {"heart_rates": req.body.data}}}},
{upsert:true, new:true, setDefaultsOnInsert: true},
(err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
else if (user) {
res.status(200).send("Updated!")
}
}
);
}
});
};

query to display subdocument not working

I'm fairly new to mongoose and I am trying to write a query that just returns a subdocument within my main document.
My document structure is like this:
PROFILE
- CONTACTS [ARRAY]
I've written the following endpoint to return one contact, where I pass the profile id and the id of the subdocument:
"/:owerId/getcontact/:contactId"
My Express function code looks like this:
router.route('/:ownerId/getcontact/:contactId')
.get(function(req, res){
Profile.findOne({'owner_id':req.params.ownerId}).then(function(err, profile){
if(err)
res.send(err);
profile.findOne({'_id':req.params.contactId}).then(function(err, contact){
if(err)
res.send(err);
res.json(contact);
})
})
})
But this code returns the whole profile.
When I try to get by ID it does the same thing. Here is my code and just below that is the entire profile that is returned:
router.route('/:ownerId/getcontact/:contactId')
.get(function(req, res){
Profile.findById(req.params.ownerId).then(function(err, profile){
if(err)
res.send(err);
var data = profile.contacts.id(req.params.contactId);
res.json(data);
})
})
{
"_id": "5886e3692ca4542c453431ee",
"initial": "u",
"last_name": "randal",
"first_name": "chris",
"owner_id": "5886e32c2ca4542c453431ed",
"__v": 1,
"contacts": [
{
"last_name": "Eltoro",
"first_name": "Peter",
"_id": "5886e3f5a219472cac886a9f",
"businesses": [],
"addresses": [],
"phones": [
{
"phone_type": "mobile",
"phone_number": "555-555-999",
"_id": "5886e3f5a219472cac886aa2"
},
{
"phone_type": "home",
"phone_number": "999-876-000",
"_id": "5886e3f5a219472cac886aa1"
}
],
"emails": [
{
"email_address": "tim#time.com",
"_id": "5886e3f5a219472cac886aa0"
}
]
},
{
"college": "University of WA",
"highschool": "Kalaheo",
"birthday": "1990-12-22T08:00:00.000Z",
"last_name": "Smith",
"first_name": "Suzanne",
"_id": "5886fb7fac288c2e31eabe0a",
"businesses": [],
"addresses": [
{
"zip": "98777",
"state": "WA",
"city": "Seattle",
"address_2": "Apt 234",
"address": "124 194th St. SW",
"_id": "5886fb7fac288c2e31eabe0e"
}
],
"phones": [
{
"phone_type": "mobile",
"phone_number": "206-899-9898",
"_id": "5886fb7fac288c2e31eabe0d"
},
{
"phone_type": "home",
"phone_number": "206-789-0987",
"_id": "5886fb7fac288c2e31eabe0c"
}
],
"emails": [
{
"email_type": "personal",
"email_address": "suzanne#smith.com",
"_id": "5886fb7fac288c2e31eabe0b"
}
]
},
{
"last_name": "Alabaster",
"first_name": "Cindy",
"_id": "5888b0bd3c025e54476828d9",
"businesses": [],
"addresses": [],
"phones": [
{
"phone_type": "home",
"phone_number": "999-999-0909",
"_id": "5888b0bd3c025e54476828dc"
},
{
"phone_type": "home",
"phone_number": "000-000-0000",
"_id": "5888b0bd3c025e54476828db"
}
],
"emails": [
{
"email_address": "Some#them.com",
"_id": "5888b0bd3c025e54476828da"
}
]
}
],
"businesses": [],
"addresses": [],
"phones": [
{
"phone_number": "999-999-9999",
"phone_type": "mobile",
"_id": "5886e37f2ca4542c453431ef"
}
],
"emails": []
}
Mongoose sub documents have special methods to retrieve them:
router
.route('/:ownerId/getcontact/:contactId')
.get(function(req, res) {
Profile.findOne({ owner_id: req.params.ownerId }, function(err, profile) {
if ( err ) {
res.send(err);
}
var contact = profile.contacts.id(req.params.contactId);
res.json(contact);
});
});
See Mongoose Sub Documents.
Another route is through the aggregation framework where you can use the $match, $arrayElemAt and $filter operators to return the data you want.
Consider running the following aggregate operation in your API endpoint implementation:
router.route('/:ownerId/getcontact/:contactId')
.get(function(req, res){
var ownerId = mongoose.Schema.Types.ObjectId(req.params.ownerId),
contactId = mongoose.Schema.Types.ObjectId(req.params.contactId);
Profile.aggregate([
{ "$match": { "owner_id": ownerId } },
{
"$project": {
"contact": {
"$arrayElemAt": [
{
"$filter": {
"input": "$contacts",
"as": "contact",
"cond": { "$eq": ["$$contact._id", contactId] }
}
},
0
]
}
}
}
]).exec(function(err, profile){
if(err) res.send(err);
res.json(profile[0].contact);
})
})

Mongoose get only objects from array matching element inside the object

I'm trying to obtain the objects inside the reviews array by matching the fb_id's that I'm passing. I do not seem to get them to work. This is my actual document in the DB
{
"_id": {
"$oid": "5841d18187dcc74805887a6a"
},
"product_id": "583ae172231f5ec01db5727e",
"category": "Smartphones",
"reviews": [
{
"fb_id": "111",
"name": "name1",
"user_img": "imgurl1",
"title": "asdakj",
"description": "jnkjnkj",
"rating": 5,
"_id": {
"$oid": "5841d18187dcc74805887a6b"
}
},
{
"fb_id": "222",
"name": "name2",
"user_img": "imgurl2",
"title": "dadad",
"description": "asdasdad",
"rating": 3,
"_id": {
"$oid": "5841d1d0cbdf333411530ebd"
}
},
{
"fb_id": "333",
"name": "name3",
"user_img": "img url3",
"title": "asdad",
"description": "asdads",
"rating": 5,
"_id": {
"$oid": "5841d4c2174270f807084721"
}
},
{
"fb_id": "444",
"name": "name4",
"user_img": "imgurl4",
"title": "adasd",
"description": "kjnkj",
"rating": 1,
"_id": {
"$oid": "5841d569eae1b6600ea1ca92"
}
}
],
"__v": 0
}
I will be sending an array of fb_id's to mongoose and want the results only for the objects inside the array that has the fb_id's.
This is my query now:
Review.find({ product_id: '583ae172231f5ec01db5727e' }, { 'reviews.$.fb_id': { $in: <array of fb_id> } }, function(err, results) {
if (err) {
throw err;
};
console.log(results)
});
But it gives me this error :
MongoError: Unsupported projection option: reviews.$.fb_id: { $in: [ 111.0 ] }
EDIT: After a small query, now I am to get some results. But the result has only the first object that match from the fb_id's and not all.
Please tell me how I can achieve this.
You can use this for reference.
your code would be something like this:
Review.find({
product_id: '583ae172231f5ec01db5727e'
},
{
reviews: {
$elemMatch: {
fb_id: {
$in: <array of fb_id>
}
}
}
},
{
_id: 0,
'reviews.$': 1
}
, function(err, results) {
if (err) {
throw err;
};
console.log(results)
});

Resources