How to find an object inside an array inside a mongoose model? - node.js

I'm trying to query an object that's inside an item which is inside a mongoose model, when I'm trying to find that object with the find() method or _.find() method, I can't get access to the object for some reason and when I console.log() it, it gives me undefined or when I use array.filter() it gives me an empty array, which means the object that I'm trying to access does not meet the criteria that I give it in the lodash find method, but then when I look at my database I see that the object does actually have the properties to meet the criteria. So I don't know what I'm doing wrong, here's my code: as you can see I'm trying to get the information of the item that the user clicked on and want to see:
router.get("/:category/:itemId", (req, res) => {
console.log(req.params.itemId);
//gives the item id that the user clicked on
console.log(req.params.category);
//gives the name of category so I can find items inside it
Category.findOne({ name: req.params.category }, (err, category) => {
const items = category.items; //the array of items
console.log(items); //gives an array back
const item = _.find(items, { _id: req.params.itemId });
console.log(item); //gives the value of 'undefined' for whatever reason
});
});
The category Schema:
const catSchema = new mongoose.Schema({
name: {
type: String,
default: "Unlisted",
},
items: [
{
name: String,
price: Number,
description: String,
img: String,
dateAdded: Date,
lastUpdated: Date,
},
],
dateCreated: Date,
lastUpdate: Date,
});

well the answer is a little bit obvious, you are using MongoDB and in Mongo you have "_ID" you can use that "_ID" only with Mongoose! so you just have to remove the underscore and that is it! do it like this const item = _.find(items, { id: req.params.itemId });

hope you are doing better.
When I look at your Schema I see that the item field is an array of objects which doesn't have an _id inside so when you create a new instance of catShema it just generates an _id field for the new instance but not for each item inside the items array, just also enter the id of the item in question because according to my understanding, you must also have a model called items in your database
When you save these records in your database, you will generate an element with this structure
{
_id: String, // auto generated
name: String,
items: [ {"name1", "price1", "description1", "imgUrl1", "dateAdded1", "lastUpdated1"},{"name2", "price2", "description2", "imgUrl2", "dateAdded1", "lastUpdated2"}, ...],
dateCreated: Date,
lastUpdate: Date
}
Note : the code provided at the top is only an illustration of the object which will be registered in the database and not a valid code
Here you can notice that there is not a field called _id in the object sent inside the database.
My suggestion to solve this issue is
To create an additional field inside the items array called _id like :
{
...,
items: [
{
_id: {
type: String,
unique : true,
required: true // to make sure you will always have it when you create a new instance
},
...
... // the rest of fields of items
},
...
Now when you create a new instance make sure in the object you enter in the database the _id is recorded when you call the catInstance.save() so inside the catInstance object you have to add the current Id of the element to be able to filter using this field.
Hope my answer helped, if you have any additional questions, please let me know
Happy coding ...

Related

Is it possible to search for keys within an object within a field within a document in mongoDB?

I have a form on a page, I want a user to enter something in the form click submit, then make a request to MongoDB using the input of that form and render parts of that request onto a page, using nodejs, mongoose, and ejs
The schema of the collection has a field that always contains an object and I would like to search for a document in the collection that has a key that matches the input of the form.
The schema of the collection is
const ArrivalTimesSchema = new mongoose.Schema({
postcodeArrivalTimes: {
type: Object,
required: true,
},
workerId: {
type: String,
required: false
},
company: {
type: String,
required: true
},
})
And an example of postcodeArrivalTimes is
postcodeArrivalTimes = {AL95AT:"07:06", DL56EP:"13:06",AL14PL:"19:15"}
So in this case if someone input AL95AT into the input form I would want this document returned, how would I do that?
Not all documents would contain the key AL95AT but there could be multiple and I would like the last.
For this I think I can use .sort({ $natural: -1 }).limit(1) within a find() but I am not sure how to search for the keys within the object within the field.
Thank you for any help!!
let input = "input" //inputKeyValue
let query = {};
query[input] = { $exists: true };
db.collection.find(query).sort({ $natural: -1 }).limit(1)

How to add new fields to the last object in an array in MongoDB?

I have an Array of objects in mongoDB as follow
Initially there is only the heartRate field inside the object. Now I want to add new fields to this object along with the existing heartRate field.
Also there can be multiple objects inside the dailyReadings array. Therefore, I need to add new fields only to the last object using nodejs and expressjs
I tried using the $push method but ended up adding new object intead of adding the fields to the last object. Is there a way to achieve this? Thanks in advance!
Why I am doing this (For further understanding):-
I have developed a mobile app to read the heart rate. Initially it will save the heart rate in the database as a new object (As in the image). Then, there are several other data sent through a desktop application which needs to add to the same object (Which is the last object in the dailyReadings array)
There is no straight way to do this, you can try update with aggregation pipeline starting from MongoDB 4.2,
$size to get total elements in dailyReadings array
$subtract to minus 1 from above total elements
$slice to get elements other than the last object element
$slice to get last object element by -1 from dailyReadings
$arrayElemAt to select first object element from array
$mergeObjects to merge existing object fields of the last object and new fields that you want to insert
$concatArrays to concat first slice array and second updated object
db.collection.update(
{}, // put your query condition
[{
$set: {
dailyReadings: {
$concatArrays: [
{
$slice: [
"$dailyReadings",
0,
{ $subtract: [{ $size: "$dailyReadings" }, 1] }
]
},
[
{
$mergeObjects: [
{ $arrayElemAt: [{ $slice: ["$dailyReadings", -1] }, 0] },
{
newField: "1"
}
]
}
]
]
}
}
}]
)
Playground
In order for you to add fields to the last object, the heartRate should be an object with a schema containing the following
Array (for you to add to)
any other necessary data type you'd want the object to have
you must define a complex schema using mongoose, perform the following changes to your file of model
const mongoose = require('mongoose');
const childSchema = mongoose.Schema({
heartRate: {type: Array, required: true}
array: {type: Array, required: false}, //change the required parameter based on your requirement
});
const parentSchema = mongoose.Schema({
dailyReadings: {
type: childSchema,
required: false //change the required parameter based on your requirement
},
});
module.exports = mongoose.model('modelCollection', parentSchema);
So basically you need to define the child schema, and change the type of dailyReadings to that schema and add to the array of different objects.

MongoDB update query in subarray

An update in the array of objects inside another array of objects.
mongodb field that I'm working on:
otherFields: values,
tasks: [
{
_id: mongodb.objectID(),
title: string,
items:[{
_id: mongodb.objectID(),
title: string,
completed: boolean //field need to be update.
}]
},
{}...
],
otherFields: value
sample mongodb document
I need to find the document using the task_id and the item_id and update a completed field in item of a task. Using the mongoose findOneAndUpdate method
const path = "tasks.$.items." + item_id + "completed";
collectionName.findOneAndUpdate(
{ _id: req.user._id, "tasks._id": taskID },
{ $set: { [path]: true }});
The above query doesn't work!!!
There is no need to use multiple query conditions, since you'd like to update a specific item that has an unique ID. Therefore you could use something along the lines:
collectionName.findOneAndUpdate(
{ 'tasks.items._id': itemID },
...
);
Keep in mind this structure is far away from optimized as it would basically look through the entire database...
Also now that I think of it, you'd also have issue with the update, as there are two nested arrays within the document. Read more here: How to Update Multiple Array Elements in mongodb

updating a data object in nested array in mongodb by mongoose

i have a serious problem in updating my data . i have no idea how i can update a specific field in an object of an array in my document .
here is my Schema model :
var shiftSchema = new Schema({
Phone: String,
final: Boolean,
statusSH: String,
order: {
startTime: String,
finishTime: String,
income: String,
orders: [{
stat: String,
orderId: String,
customerPhone: String,
orderQuantity: String,
orderCost: String,
orderCondition: String,
orderTag: String
}]
}
});
when i use "find" it gives me the document and not just the object.
now how can i edit "stat" by finding "orderId" ?
Note that i do not have the index of the object that i want to update and i can just use "find"or "findOne".
i search all over the web and i couldn't find a good guide and example .
sorry for my bad english.
All tips will be appreciated. Thank You.
You can try to run this query, to update the stat property:
shiftSchema.updateOne({
'order.orders.orderId': 'id'
}, {
'$set': {'order.orders.$.stat': 'newStatus'}
})
.then((result) => {
console.log(result)
}, (e) => {
console.log(e)
})
You can see I used positional $ operator to access an element in the array and update it without specifying the position of the element (with index).
I also used $set to replace the value of a field.
With just find or findOne you will not make the actual update.

Mongoose find with default value

I have a mongoose model: (With a field that has a default)
var MySchema= new mongoose.Schema({
name: {
type: String,
required: true
},
isClever: {
type: Boolean,
default: false
}
});
I can save a model of this type by just saving a name and in mongoDB, only name can be seen in the document (and not isClever field). That's fine because defaults happen at the mongoose level. (?)
The problem I am having then is, when trying to retrieve only people called john and isClever = false:
MySchema.find({
'name' : 'john',
'isClever': false
}).exec( function(err, person) {
// person is always null
});
It always returns null. Is this something related to how defaults work with mongoose? We can't match on a defaulted value?
According to Mongoose docs, default values are applied when the document skeleton is constructed.
When you execute a find query, it is passed to Mongo when no document is constructed yet. Mongo is not aware about defaults, so since there are no documents where isClever is explicitly true, that results in empty output.
To get your example working, it should be:
MySchema.find({
'name' : 'john',
'isClever': {
$ne: true
}
})

Resources