multiple search and filter data returning count of each filter in nestjs mongodb - mongodb

I want to filter the items in the database by their fields and also return the count of each filter.
Example is when I select to return specific brand names I want to see the number of brand name available.
Is there any search service I could use like Azure search or a way to implement this in NestJs and mongodb
This is the Database collection
{
"brand": "Screaming Eagle, The Flight",
"producer": "Screaming Eagle",
"productionCountry": "America",
"region": "Napa Valley",
"appellation": "Oakville",
"vintage": "2016",
"grape": "Cabernet Sauvignon",
"maturity": "25",
"case": "3 bottles",
"origin": "SECONDARYMARKET",
"type": "Red"
},{
"brand": "Joseph Phelps, Insignia",
"producer": "Joseph Phelps",
"productionCountry": "America",
"region": "Napa Valley",
"appellation": "St. Helena",
"vintage": "2012",
"grape": "Cabernet Sauvignon",
"maturity": "25",
"case": "6 bottles",
"origin": "SECONDARYMARKET",
"type": "Red"
},{
"brand": "Joseph Phelps, Insignia",
"producer": "Joseph Phelps",
"productionCountry": "America",
"region": "Napa Valley",
"appellation": "St. Helena",
"vintage": "2012",
"grape": "Cabernet Sauvignon",
"maturity": "25",
"case": "6 bottles",
"origin": "SECONDARYMARKET",
"type": "Red"
},{
"brand": "Continuum",
"producer": "Continuum",
"productionCountry": "America",
"region": "Napa Valley",
"appellation": "Oakville",
"vintage": "2017",
"grape": "Cabernet Sauvignon",
"maturity": "26",
"case": "6 bottles",
"origin": "SECONDARYMARKET",
"type": "Red"
},{
"brand": "Continuum",
"producer": "Continuum",
"productionCountry": "America",
"region": "Napa Valley",
"appellation": "Oakville",
"vintage": "2017",
"grape": "Cabernet Sauvignon",
"maturity": "26",
"case": "6 bottles",
"origin": "SECONDARYMARKET",
"type": "Red"
}

This is known as "facets" and it is supported by Azure Cognitive Search and MongoDB. In Azure Cognitive Search, you have to set facetable to true for the fields you'd like to get counts for, such as brand then specify in the query "facets": ["brand"].
For more information Azure Search see: https://learn.microsoft.com/en-us/azure/search/search-faceted-navigation
This works in MongoDb using the $facet aggregation operator which you can read more about here: https://www.mongodb.com/docs/manual/reference/operator/aggregation/facet/

Related

How to update specific field in mongoDB given conditions?

Given the following mongdoDB structure, how can i update the field isAvailable to false given that the shopName is "jamrt" and slug is "67626dae-1537-40d8-837d-483e5759ada0". This is my query but it does not work: Shop.find({ shopName: shopName}).update({products: {$elemMatch: {slug: slug}}}, { $set: { isAvailable: req.body.isAvailable} } Thanks!
"shopName": "jmart",
"products": [{
"id": 1,
"name": "Clean and Clear Deep Clean Cleanser 100g",
"slug": "8d1c895c-6911-4fc8-a34c-89c6948233d7",
"price": 4.5,
"discount_price": 0,
"category": "Health and Beauty",
"sale": false,
"subcategory": "personal care",
"color": "black",
"article": "Clean and Clear",
"quantity": 9,
"img": "https://firebasestorage.googleapis.com/v0/b/swifty-products.appspot.com/o/Jmart%2FBeauty%2FClean%20and%20Clear%20Deep%20Clean%20Cleanser%20100g.jpg?alt=media",
"vendor": {
"id": 1,
"name": "Clean and Clear"
},
"ratings": {
"star_ratings": 0,
"votes": 0
},
"isAvailable": true
}, {
"id": 2,
"name": "Colgate Total Pro Breath Health",
"slug": "67626dae-1537-40d8-837d-483e5759ada0",
"price": 4.5,
"discount_price": 0,
"category": "Health and Beauty",
"sale": false,
"subcategory": "personal care",
"color": "black",
"article": "Colgate",
"quantity": 9,
"img": "https://firebasestorage.googleapis.com/v0/b/swifty-products.appspot.com/o/Jmart%2FBeauty%2FColgate%20Total%20Pro%20Breath%20Health.jpg?alt=media",
"vendor": {
"id": 2,
"name": "Colgate"
},
"ratings": {
"star_ratings": 0,
"votes": 0
},
"isAvailable": true
},
]
In your case, you are trying to update only the matching sub documents.
The $elemMatch operator while using in projection updates only the first matching sub document.
The $elemMatch operator while using in find updates all the fields of the matching document.
This solution might help you.
With your case, the solution might be the below in mongodb query:
db.Shop.update({"shopName":"jmart","products.slug":"67626dae-1537-40d8-837d-483e5759ada0"}, {$set: {“products.$[i].isAvailable”: false}}, {arrayFilters: [{“i.slug”: "67626dae-1537-40d8-837d-483e5759ada0"}]})

Query in Embedded document

I want to do a query where i can reach all banks where bank is banco1 and investments are not equal to "box".
How can i do that? I tried this query, but don't work :
db.banks.find( { "investments": { $elemMatch: { bank: "banco1", productName: {$ne:"box} } } } );
This query it's one example of many that i have tried.
Thanks.
{
"_id": "5d3fc8c3914297c7b9a3a9e5",
"banco": "banco 1",
"investimentos": [{
"bank": "banco1",
"risk": "Conservador",
"expiryDate": "2021-10-04",
"tax": "1.02",
"discriminator": "investment",
"productName": "LCI"
},
{
"bank": "banco1",
"risk": "Conservador",
"expiryDate": "2020-06-24",
"tax": "0.75",
"discriminator": "investment",
"productName": "Fundo DI"
},
{
"bank": "banco1",
"risk": "Conservador",
"tax": "0.04",
"discriminator": "investment",
"id": "259ad8ac-57b7-4d33-8e75-46cf5c5c28e3",
"aniversary": "30",
"productName": "box"
}
}],
{
"_id": "5d3fcb4c914297c7b9a3a9e6",
"banco": "banco2",
"investimentos": [{
"bank": "banco2",
"risk": "Conservador",
"expiryDate": "2020-06-24",
"tax": "0.80",
"discriminator": "investment",
"id": "73db503f-c780-448c-a6a8-05d2837ff6ff",
"redemptionDate": "D+1",
"productName": "Fundo DI"
}
,
{
"bank": "banco2",
"risk": "Conservador",
"expiryDate": "2020-12-17",
"tax": "0.98",
"discriminator": "investment",
"id": "54e01515-dc7f-470f-8f00-8603c8f00686",
"productName": "LCA"
},
{
"bank": "banco2",
"risk": "Conservador",
"expiryDate": "2021-08-05",
"tax": "1.0",
"discriminator": "investment",
"id": "259ad8ac-57b7-4d33-8e75-46cf5c5c28e2",
"productName": "CDB"
}
}]
Welcome to SO Luan!
I've found that Mongo Aggregations give me all of the power available in find, and so much more functionality. So about 95% of the time, unless I'm doing a quick query, I end up going to aggregates.
The following aggregate will get you what you're looking for:
db.getCollection('Test').aggregate([
{ $unwind: "$investimentos"},
{ $match: {
'investimentos.bank': "banco1",
'investimentos.productName': /^(?!box$)/
}},
])
The $unwind pipeline takes the array of embedded documents in investimentos, and creates a new document, retaining the parent fields (_id and banco), for each element withing investimentos. You can try just db.getCollection('Test').aggregate([{ $unwind: "$investimentos"}]) to visually see what happens.
The $match pipeline does the same thing as the find method - you give it a list of filters to apply. The second element uses a regex (surrounded by '/' chars) to specify that it should find everything that does not start with "box".

How to query api with filter options

I am trying filter the response city wise. I am not able to understand how to query filter parameters.
I have tried different ways but with no success. This is the response without applying filter. But I want filter it for a particular city.
{
"index_name": "3b01bcb8-0b14-4abf-b6f2-c1bfd384ba69",
"title": "Real time Air Quality Index from various location",
"desc": "Real time Air Quality Index from various location",
"org_type": "Central",
"org": [
"Ministry of Environment and Forests",
"Central Pollution Control Board"
],
"sector": [
"Industrial Air Pollution"
],
"source": "data.gov.in",
"catalog_uuid": "a3e7afc6-b799-4ede-b143-8e074b27e0621",
"visualizable": "1",
"active": "1",
"created": 1543320551,
"updated": 1559683085,
"created_date": "2018-11-27T17:39:11Z",
"updated_date": "2019-06-05T02:48:05Z",
"target_bucket": {
"index": "air_quality",
"type": "a3e7afc6-b799-4ede-b143-8e074b27e0621",
"field": "3b01bcb8-0b14-4abf-b6f2-c1bfd384ba69"
},
"field": [
{
"id": "id",
"name": "id",
"type": "double"
},
{
"id": "country",
"name": "country",
"type": "keyword"
},
{
"id": "state",
"name": "state",
"type": "keyword"
},
{
"id": "city",
"name": "city",
"type": "keyword"
},
{
"id": "station",
"name": "station",
"type": "keyword"
},
{
"id": "last_update",
"name": "last_update",
"type": "date"
},
{
"id": "pollutant_id",
"name": "pollutant_id",
"type": "keyword"
},
{
"id": "pollutant_min",
"name": "pollutant_min",
"type": "double"
},
{
"id": "pollutant_max",
"name": "pollutant_max",
"type": "double"
},
{
"id": "pollutant_avg",
"name": "pollutant_avg",
"type": "double"
},
{
"id": "pollutant_unit",
"name": "pollutant_unit",
"type": "keyword"
}
],
"status": "ok",
"message": "Resource detail",
"total": 1000,
"count": 10,
"limit": "10",
"offset": "8",
"records": [
{
"id": "13",
"country": "India",
"state": "Andhra_Pradesh",
"city": "Rajamahendravaram",
"station": "Anand Kala Kshetram, Rajamahendravaram - APPCB",
"last_update": "05-06-2019 02:00:00",
"pollutant_id": "CO",
"pollutant_min": "2",
"pollutant_max": "50",
"pollutant_avg": "28",
"pollutant_unit": "NA"
},
{
"id": "14",
"country": "India",
"state": "Andhra_Pradesh",
"city": "Rajamahendravaram",
"station": "Anand Kala Kshetram, Rajamahendravaram - APPCB",
"last_update": "05-06-2019 02:00:00",
"pollutant_id": "OZONE",
"pollutant_min": "37",
"pollutant_max": "132",
"pollutant_avg": "71",
"pollutant_unit": "NA"
}
{
"id": "16",
"country": "India",
"state": "Andhra_Pradesh",
"city": "Tirupati",
"station": "Tirumala, Tirupati - APPCB",
"last_update": "05-06-2019 02:00:00",
"pollutant_id": "PM10",
"pollutant_min": "33",
"pollutant_max": "72",
"pollutant_avg": "55",
"pollutant_unit": "NA"
}
],
"version": "2.1.0"
}
This is only documentation on how to do filtering.
properties: OrderedMap { "id": OrderedMap { "type": "integer" }, "date": OrderedMap { "type": "integer" } }
How to form request url for filtering the response?
yes the documentation is very poor, but still out of many trials I got it work like
this
https://api.data.gov.in/resource/3b01bcb8-0b14-4abf-b6f2-c1bfd384ba69?api-key=<your key>&format=json&offset=0&limit=10
&filters[pollutant_id]=NO2

mongoDB search query

For an assignment, we are given the following code:
db.bib.insertMany( [
{type : "book",
"#year": "1994",
"title": "TCP/IP Illustrated",
"author": {
"last": "Stevens",
"first": "W."
},
"publisher": "Addison-Wesley",
"price": "65"
},
{type : "book",
"#year": "1992",
"title": "Unix Programming",
"author": {
"last": "Stevens",
"first": "W."
},
"publisher": "Addison-Wesley",
"price": "65"
},
{type : "book",
"#year": "2000",
"title": "Data on the Web",
"author": [
{
"last": "Abiteboul",
"first": "Serge"
},
{
"last": "Buneman",
"first": "Peter"
},
{
"last": "Suciu",
"first": "Dan"
}
],
"publisher": "Morgan Kaufmann",
"price": "39"
},
{type : "book",
"#year": "1999",
"title": "Digital TV",
"editor": {
"last": "Gerbarg",
"first": "Darcy",
"affiliation": "CITI"
},
"publisher": "Kluwer",
"price": "130"
}
,
{type : "journal",
"title": "Irreproducible results",
"editor": {
"last": "Self",
"first": "W."
},
"publisher": "SV"
}
])
Using mongoDB, we are then asked to complete different search queries in order to find the desired information. The one that I am currently stuck on is
List the titles of books published after 1995 and costing less than 100.
From my understanding, the proper query should be something along the lines of
db.bib.find({price: {$lt: 100}, year: {$gt: 1995}}, {title: 1, _id: 0})
However, this provides a blank result when it should not. Why is this and how can I fix it?
Data type for both of the field is string. you can not compare them as numeric. Try following and it will work. using collation, you can ask MongoDB to treat them as int. you can read more about collation here at mongodb.com.
db.bib.find({$and: [{"#year": {$gt: "1995"}}, {price: {$lt: "100"}}]}).collation({
locale: "en_US",
numericOrdering: true
});

Finding values in mongodb collection with multiple occurence

I have a collection with documents as follows :
{id: 1, "year": "12", "type": "checking", "location": "nyc", "category" : "Admin"}
{id: 2, "year": "15", "type": "checking", "location": "ma", "category": "Normal"}
{id: 3, "year": "12", "type": "credit", "location": "nyc","category": "Admin"}
{id: 4, "year": 12, "type": "checking", "location": "nyc", "category" : "Admin"}
Now, i want to count the 'type' that appears more than once meeting the criteria location:nyc, year:12, category: Admin
So the desired result is
{"Checking": 2}
What way can I achieve the above?
Use $match and $group
db.collectionname.aggregate({$match: {location: 'nyc', year:'12', category:'Admin'}},
{$group: {_id:'$type', count:{$sum:1}}},
{$match:{count: {$gt:1}}}
)