Querying a sub document of a sub document in mongoose - node.js

Inside my parent I have many childs and in one of them childs they also have many sub childs, I need to return the sub childs from a specific child.
exports.test = (req, res) => {
Forum.find({title: req.params.id}).then(record => {
console.log(record);
})
};
The code here returns the following when I insert the News & Announcement url param which is correct:
_id: 5e7bf52ebb5b2b09fb46e29f,
title: 'News & Announcements',
property: 'ACP',
position: 1,
visible: true,
topics: [ [Object], [Object], [Object] ],
__v: 5 } ]
I then want to access the topics and return a specific topic - finding it by a name/title as I did above, how would I do this?

If this topics field is an array of objects and each object contains the name and title, then you can search for the topic you want, just add that to the object you passed to the find query
for example, If you need to query for some topic with name 'My Topic', then the query should be
Forum.find({ title: req.params.id, 'topics.name': 'My Topic' })
this will narrow down the results of the query but if there are some other topics with different names in the same forum, they will be come with you in the query
for example, if some forum has the following info:
{
_id: ObjectId("5e7bf52ebb5b2b09fb46e29f"),
title: 'News & Announcements',
property: 'ACP',
position: 1,
visible: true,
topics: [
{
name: 'Topic 1',
title: 'Title 1'
}, {
name: 'Topic 2',
title: 'Title 2'
}, {
name: 'My Topic',
title: 'My Title'
}
],
}
and you search for the topic 'My Topic' only in this forum, all the topics array will be returned from the query, as the search is done per documents
so you have to do some javaScript trick after finishing the query to get only the topic that has the name you wanted
var myTopic = record.ropics.filter(topic => topic.name === 'My Topic'}
this will return the topic you wanted only

Related

implement a search functionality that query MongoDB database and return all the objects which contain a user given value in node js and express

I want to implement a search functionality that would query my MongoDB database and return all the objects which contain (full/partially) the name I am searching for.
Example:
My object collection is products, and I want to see every product which contains the name I search, from the product names.
My 'Products' collection looks like this...
[ { _id: 5f79,
productName: 'Test-image12345',
price: 60,
details: 'Test product' },
{ _id: 5f7d,
productName: 'Test-image1234',
price: 60,
details: 'Test product'},
{ _id: 5fv4,
productName: 'Test',
price: 60,
details: 'Test product'},
]
Now I need to find all the products with "Test-image1234"
// search a product by name
productRoute.get('/getproduct/:name', async (req,res) => {
try {
const findname = req.params.name;
const objs = await Product.find({productName:{ $regex:'.*'+findname+'.*'} });
res.json(objs);
} catch (error) {
res.json({message: error});
}
})
Now I get the answer as follows...
[ { _id: 5f79,
productName: 'Test-image12345',
price: 60,
details: 'Test product' },
{ _id: 5f7d,
productName: 'Test-image1234',
price: 60,
details: 'Test product'}
]

mongoose: Finding an id that is nested?

I'm sorry if this is a repetitive question, but I'm yet to find a solution after scouring the internet for hours :( . I have a database for storing tasks ( a todo list app ) and then I have another so you can make custom todo list with different todos ect...
this database stores the name and an array of the items of the other schema with the specific todos.
const listSchema = {
name: String,
items: [itemSchema]
}
the database looks like this:
[
{
_id: 5ea083694f1d7d0db432b939,
name: 'home',
items: [ [Object], [Object] ],
__v: 2
}
]
and in the items array it looks like this:
[
{ _id: 5ea083764f1d7d0db432b93a, name: 'some todo', check: false },
{
_id: 5ea08391ab923b36780429ee,
name: 'some other todo',
check: false
}
]
What I want to do is find and update by a specific id in the items array, I have the variables
const id = req.body.check // in a for loop and gets id of the specific item
const titleName = req.body.titleName; // gets the title name of the parent object of the items array
and it needs to find using the titleName and the id so that I can update the "check: false" so that it's "check: true"
.
.
.
Found Solution:
List.updateOne({"items._id" : id}, {"$set": {"items.$.check": true}})
You can use findOneAndUpdate(filter, update) of mongoose
const id = req.body.id;
const titleName = req.body.titleName;
collectionName.findOneAndUpdate({"items.id": id, "name": titleName}, {"check": true})

API to insert data to array of objects in mongoDB

I am trying to insert array of objects inside array of objects in my mongoDB schema. This is how i want my schema to appear.
const CourseSchema = mongoose.Schema({
categoryname: {
type: String,
required: "Course Category",
min: 3,
max: 100
},
coursename: {
type: String,
required: "Course Name",
min: 3,
max: 100
},
levels:
[
{
levelid: Number,
levelname: String,
chapter:
[
{
chapternumber: Number,
chaptername: String,
content: String //To be elaborated
}
]
}
]
});
My API which i have written looks like this:
exports.addcourse = (req, res) => {
let levels = [];
levels.push({
levelid: req.body.levelid,
levelname: req.body.levelname,
chapter: [
{
chapternumber: req.body.chapternumber,
chaptername: req.body.chaptername,
content: req.body.content
}
]
})
const newCourse = new Course({
coursename: req.body.coursename,
categoryname: req.body.categoryname,
levels: levels
});
newCourse.save(function (error) {
if (error) res.json({ message: 'could not add course because ' + error });
res.json({ newCourse: newCourse });
});
}
This works fine when i enter one level and one chapter, but gives an error when i enter multiple data.
I am giving input from postman 'x-www'form-urlencoded'.
please help.
The error i get when i add one more levelid and levelname in postman
{
"message": "could not add course because ValidationError: levels.0.levelid: Cast to Number failed for value \"[ '1', '2' ]\" at path \"levelid\", levels.0.levelname: Cast to String failed for value \"[ 'First Level', 'Second Level' ]\" at path \"levelname\""
}
The data i am trying to enter
In postman, when you are sending the same key levelid twice, it converts it to array containing both the values. Like in your case, in req.body.levelid, you will receive [1, 2]. But in your schema, levelid is expecting a number value. Also, you are reading it wrong in your API code. Instead of getting levelid and chapter seperately, you can get the levels array in request body with values levelid, levelname and chapter. Similarly, chapter can be an array of objects. req.body.levels will look like this:
[{
levelid: 1,
levelname: "level1",
chapter: [{
chapternumber: 1,
chaptername: "chapter1",
content: "chapter1-content"
}, {
chapternumber: 2,
chaptername: "chapter2",
content: "chapter2-content"
}]
}]
Try this in postman by giving input in raw

querying nested object arrays from mongodb / nodejs

I am trying to figure out how to query the nested objects inside the Components object. The data was inserted from a parsed json file.
Query
var query = {}
cursor = db.collection("workflows").find(query).toArray(function(err, result) {
if (err) throw err;
console.log(result);
db.close();
});
This data is returned when I run the query above:
At this point i'm just trying to get it to filter in some manner. I've tried Name:'Test WF' and other variations of that but still can't get a filtered response.
[ { _id: 5c77040838f9d322b89bbd82,
texto:
{ _id: 12,
LocalCachePath: 'Z:\\Test\\Cache',
SharedCachePath: [],
Name: 'Test WF',
Desc: 'I\'m testing',
Components: [Array] } },
{ _id: 5c7704164413692978a9dd1a,
texto:
{ _id: 'Workflow-2019.02.22-23.21.15-MKRU',
LocalCachePath: 'Z:\\MAITest\\Cache',
SharedCachePath: [],
Name: 'Test WF',
Desc: 'I\'m testing',
Components: [Array] } },
{ _id: 5c77046335b012379c99951b,
texto:
{ _id: '154',
LocalCachePath: 'Z:\\Test\\Cache',
SharedCachePath: [],
Name: 'Test WF',
Desc: 'I\'m testing',
Components: [Array] } },
{ _id: 5c7704787bde6f36543d1016,
texto:
{ _id: 'Workflow-2019.02.22-23.21.15-MKRU',
LocalCachePath: 'Z:\\Test\\Cache',
SharedCachePath: [],
Name: 'Test WF',
Desc: 'I\'m testing',
Components: [Array] } } ]
Any insight would be helpful i'm stumbling through this one step at a time.
Here's another query that is giving me results but i guess my issue is going to be to parse out my results as variables.
var query = {'texto.Components.0.Name' : {$gt: ''}}
// var query = {'testo.Name' : {$gt: ''} }
cursor = db.collection("workflows").find(query).toArray(function(err, result) {
if (err) throw err;
Use dot notation (e.g. texto.Name) to query and retrieve fields from nested objects, example:
var query = {'texto.Name': 'Test WF'}
Simply
db.getCollection('TestQueries').find({'texto.Name': 'Test WF'})
Regex used for Case Insensitive.
db.getCollection('TestQueries').find({"texto.Name":{
'$regex' : '^test wa$', '$options' : 'i'
}})
Using collation
db.fruit.createIndex( {"texto.Name": 1},{ collation: {
locale: 'en', strength: 2
} } )
db.getCollection('TestQueries').find(
{ "texto.Name": "test wa" } ).collation( { locale: 'en', strength: 2 }
)
You can also use $elemMatch. It is longer, but allows for multiple fields query.
db.getCollection('TestQueries').find({texto: {$elemMatch: {Name: "test wa"} }))
Official docs here

Grid store config throws "Uncaught TypeError: Cannot read property 'buffered' of undefined"

I have form and grid. the user must enter data in form fields then display related records in the grid.
I want to implement a search form, e.g: user will type the name and gender of the student,
then will get a grid of all students have the same name and gender.
So, I use Ajax to send form fields value to PHP and then create a json_encode which will be used in grid store.
I am really not sure if my idea is good. But I haven't found another way to do that.
The problem is there is a mistake in my store but I couldn't figure out what it is. I get this error:
Uncaught TypeError: Cannot read property 'buffered' of undefined
My View:
{
xtype: 'panel',
layout: "fit",
id: 'searchResult',
flex: 7,
title: '<div style="text-align:center;"/>SearchResultGrid</div>',
items: [{
xtype: 'gridpanel',
store: 'advSearchStore',
id: 'AdvSearch-grid',
columns: [{
xtype: 'gridcolumn',
dataIndex: 'name',
align: 'right',
text: 'name'
}, {
xtype: 'gridcolumn',
dataIndex: 'gender',
align: 'right',
text: 'gender'
}
],
viewConfig: {
id: 'Arr',
emptyText: 'noResult'
},
requires: ['MyApp.PrintSave_toolbar'],
dockedItems: [{
xtype: 'PrintSave_tb',
dock: 'bottom',
}]
}]
}
My Controller:
.
.
.
xmlhttp.open("GET","AdvSearch.php?search_name="+search_name,true);
xmlhttp.send(null);
My PHP script:
if (!$con) {
throw new Exception("Error in connection to DB");
}
$query ="SELECT name, gender FROM students WHERE name ILIKE '%$search_name%' ";
$result = pg_query($query);
while ($row = pg_fetch_array($result)) {
$Arr[] = array('name' => $row[0], 'gender' => $row[1]);
}
$searchResult_list = array();
$searchResult_list['success'] = true;
$searchResult_list['Arr'] = $Arr;
$searchResult_list['totalCount'] = count( $searchResult_list['Arr'] );
echo json_encode($searchResult_list);
if (!$result)
die("Error in query: " . pg_last_error());
pg_close($con);
My Store, Model:
Ext.define('AdvSearchPost', {
extend: 'Ext.data.Model',
proxy: {
type: 'ajax',
url: 'AdvSearch.php',
reader: {
type: 'json',
root: 'Arr',
totalProperty: 'totalCount'
}
},
fields: [{
name: 'name'
}, {
name: 'type_and_cargo'
}
]
});
advSearchStore = Ext.create('Ext.data.Store', {
pageSize: 10,
model: 'AdvSearchPost'
});
Well it is just a typo of your storename.
The error Uncaught TypeError: Cannot read property 'buffered' of undefinedonly indicates that the store could not be bound. It may be a bit misleading.
Try the grid with either
store: advSearchPost
or
store: Ext.StoreMgr.lookup('AdvSearchPost') // if in any form a controller takes care about your store
and it will work.
Edit
I guess you haven't any controller so I recommend you to create your store like this
Ext.create('Ext.data.Store', {
pageSize: 10,
model: 'AdvSearchPost',
storeId: 'AdvSearchPost'
});
That will enable you to receive the store by the StoreManager from everywhere (after it is created). That will also enable the last statement to work without any controller.
Even if you call like this..
store: Ext.StoreMgr.lookup('bla bla bla') won't throw any error in the console.
Replace store parameter with storeId and then assign your actual store to it which will connect to your actual store. storeId:advSearchPost

Resources