How to filter in mongodb dynamically? - mongodb

I am creating app that can filter data dynamically.
If i select "John", "US", and leave the sex as blank it will return no result because the query will search a sex that is blank. I can't figure out how can i dynamically filter that in the mongodb.
ex:
var fName="John",
fCountry="US",
fSex="";
db.users.find({ $and[ {sex: fSex}, {first_name: fName}, {country: fCountry} ]})
That query will return none.
I want the code to return a answer like this if i select "John", "US":
{"_id": <object>, "first_name": "John", "sex": "Male", "country": "US"}
users:
{"_id": <object>, "first_name": "John", "sex": "Male", "country": "US"},
{"_id": <object>, "first_name": "Rex", "sex": "Male", "country": "Mexico"},
{"_id": <object>, "first_name": "Jane", "sex": "Female", "country": "Canada"}
Thank You in advance!, btw i am new to mongo
Edited

You can build the query object instead of assuming it's going to looks like a specific structure.
You can add whatever checks you'd like.
var fName="John",
fCountry="US",
fSex="";
var query = { $and: [] };
if (fName !== "") { query.$and.push({name: fName}); }
if (fCountry !== "") { query.$and.push({country: fCountry}); }
if (fSex !== "") { query.$and.push({sex: fSex}); }
db.users.find(query);
Update:
As per #semicolon's comment, the $and here is unnecessary as mongo, by default, will "and" different fields together. A simpler solution reads:
var query = {};
...
query.name = fName; // et cetera.
I'll add that it may become necessary to use the key $and and other operators when building more elaborate queries.

Related

MongoDB Project - return data only if $elemMatch Exist

Hello Good Developers,
I am facing a situation in MongoDB where I've JSON Data like this
[{
"id": "GLOBAL_EDUCATION",
"general_name": "GLOBAL_EDUCATION",
"display_name": "GLOBAL_EDUCATION",
"profile_section_id": 0,
"translated": [
{
"con_lang": "US-EN",
"country_code": "US",
"language_code": "EN",
"text": "What is the highest level of education you have completed?",
"hint": null
},
{
"con_lang": "US-ES",
"country_code": "US",
"language_code": "ES",
"text": "\u00bfCu\u00e1l es su nivel de educaci\u00f3n?",
"hint": null
}...
{
....
}
]
I am projecting result using the following query :
db.collection.find({
},
{
_id: 0,
id: 1,
general_name: 1,
translated: {
$elemMatch: {
con_lang: "US-EN"
}
}
})
here's a fiddle for the same: https://mongoplayground.net/p/I99ZXBfXIut
I want those records who don't match $elemMatch don't get returned at all.
In the fiddle output, you can see that the second item doesn't have translated attribute, In this case, I don't want the second Item at all to be returned.
I am using Laravel as Backend Tech, I can filter out those records using PHP, but there are lots of records returned, and I think filtering using PHP is not the best option.
You need to use $elemMatch in the first parameter
db.collection.find({
translated: {
$elemMatch: {
con_lang: "IT-EN"
}
}
})
MongoPlayground

What would be the best practice to perform actions on document that have list of docs that have list of docs?

I have a user document that looks like this:
{
"userId": "249869823570",
"name": "john",
"country": "usa",
"active": true,
"serviceProviders": [
{
"serviceProvidersId": "897892893",
"serviceProvidersName": "AT&T",
"active": true,
"serviceProviderContactPerson": []
},
{
"serviceProvidersId": "82589628569",
"serviceProvidersName": "T-Mobile",
"active": true,
"serviceProviderContactPerson": []
}
]
}
and I want to create 3 methods to insert/update/delete a serviceProviderContactPerson. my dilema is, my main document have array of serviceProviders, and a serviceProvider have a list of serviceProviderContactPerson...what would be the best practice in mongo to work this?
serviceProviderContactPerson document will look like this:
{
"contactId": "873498798",
"name": "Mark",
"email": "mark#tmobile.com",
"phone": "917-475-4637"
}
You can use update to perform all operations in 3.6.
Insert a new array element where serviceProvidersId = "897892893"
db.colname.update(
{"serviceProviders.serviceProvidersId":"897892893"},
{$push: {"serviceProviders.$.serviceProviderContactPerson":serviceProviderContactPersonDoc}}
)
Update phone where serviceProvidersId = "897892893" and contactId = "873498798"
db.colname.update(
{},
{$set: {"serviceProviders.$[sp].serviceProviderContactPerson.$[spc].phone":phone value}},
{arrayFilters:[{"sp.serviceProvidersId":"897892893"}, {"spc.contactId":"873498798"}]}
)
Delete array element where serviceProvidersId = "897892893" and contactId = "873498798"
db.colname.update(
{},
{$pull: {"serviceProviders.$[sp].serviceProviderContactPerson":{"contactId":"873498798"}}},
{arrayFilters:[{"sp.serviceProvidersId":"897892893"}]}
)

Embedded Documents in MongoDB

I'm having trouble understanding exactly how Embedded Documents are enforced in a soft schema such as MongoDB. if given a data-model like so:
User{
UserId:
Email:
Phone:
Reviews{
Rating:
Comment:
}//End reviews
}
Does this mean every User Document has only one review or that this is the format in which all reviews will be for a User?
Perhaps a more relational model of this would be the folloiwng:
User{
UserId:
Phone:
Email:
}
Reviews{
User:<UserID>
Rating:
Comment:
}
I know using references means a slower query but I don't understand how Embedded Documents would allow for multiple reviews.
In the case of having multiple document for the same user, MongoDB adds an unique _Id to the document every time you add a new document, so this wokrks good when you are adding multiple documents for the same user and as #wdberkeley stated, MongoDB does not enforce a schema,
"User" {
"UserId": "johndoe"
"Email": "johndoe#yahoo.com"
"Phone": "555-44444"
"Review"{
"Rating": "5"
"Comment": "this is my first comment"
}
}
"User" {
"UserId": "johndoe"
"Email": "johndoe#yahoo.com"
"Phone": "555-44444"
"Review"{
"Rating": "5"
"Comment": "this is my second comment"
}
}
"User" {
"UserId": "johndoe"
"Email": "johndoe#yahoo.com"
"Phone": "555-44444"
"Review"{
"Rating": "5"
"Comment": "this is my third comment"
}
}
In the case of one document for one user with multiple reviews, this can work fine too, can always get the document and add append reviews to it and call db.update() on the document,
"User" {
"UserId": "johndoe"
"Email": "johndoe#yahoo.com"
"Phone": "555-44444"
"Reviews"{[
{
"Rating": "5"
"Comment": "this is my first comment"
},
{
"Rating": "5"
"Comment": "this is my second comment"
},
{
"Rating": "5"
"Comment": "this is my third comment"
}
]}
}
Are you talking about how this is enforced in MongoDB or in an ODM like Mongoose? For MongoDB, the answer it simple: MongoDB doesn't enforce a schema. You can have all three of the following documents in a MongoDB collection:
{
"reviews" : {
"rating" : 9001,
"comment" : "nice scenery"
}
}
{
"reviews" : [
{
"rating" : [2, 4, 5],
"comment" : 19
},
{
"rating" : -845,
"comment" : "Powerful stuff"
}
]
}
{
"reviews" : "no"
}
In an ODM that enforces a schema application side, your notation is closest to something that would mean each document should have one reviews subdocument.

List all values existing of a property?

Assume I have a Student collection:
{
name: "ABC",
age: 10,
address {
city: "CITY1",
state: "STATE",
}
}
{
name: "DEF",
age: 11,
address {
city: "CITY2",
state: "STATE",
}
}
{
name: "ABC",
age: 12,
address {
city: "CITY1",
state: "STATE",
}
}
Can I get the list of all unique City values from the list? For example, with the above 3 documents, I would like to get the list {"CITY1", "CITY2"}
I was just getting started with MongoDB from Relational Database, so this is a little confused for me, since I needed another Address table for it and I can just use SELECT DISTINCT to get what I want.
MongoDB has a similar db.collection.distinct() command.
To access elements in the address subdocument you need to use dot notation, so the complete query would be:
db.Student.distinct("address.city")
Some helpful documentation links to help you make the translation from SQL queries:
SQL to MongoDB Mapping Chart
SQL to Aggregation Mapping Chart
Just for notes, there is already distinct as mentioned, but for a more conventional response, use aggregate:
db.Student.aggregate([
{"$unwind": "$address" }},
{"$group": { "_id": "$address.city" }},
{"$project": { "_id": 0, "city" : "$_id" }}
])
Long winded compared to distinct, but it depends on what your eyes want.

Pulling out latest (multiple) entries from MongoDB

I am trying to retrieve information on how many attempts a user takes to solve a particular problem as a JSON from a mongodb database. If there are multiple attempts on the same problem, I would only like to pull out the last entry - for instance, right now, if I do a db.proficiencies.find() - I will pull out entries A, B, C, and D but I would like to only pull out entries B and D (latest entries for the problems maze and circle respectively).
Is there an easy way to do so?
Entry A
{
"problem": "maze",
"courseLesson": "elementary_one, 1",
"studentId": "51ed51d0fcb4cc3696000001",
"studentName": "Sarah",
"_id": "51ed51defcb4cc3696000011",
"__v": 0,
"date": "2013-07-22T15:38:06.259Z",
"numberOfAttemptsBeforeSolved": 1
}
Entry B
{
"problem": "maze",
"courseLesson": "elementary_one, 1",
"studentId": "51ed51d0fcb4cc3696000001",
"studentName": "Sarah",
"_id": "51ed51defcb4cc3696000011",
"__v": 0,
"date": "2013-07-27T15:38:06.259Z",
"numberOfAttemptsBeforeSolved": 1
}
Entry C
{
"problem": "circle",
"courseLesson": "elementary_one, 1",
"studentId": "51ed51d0fcb4cc3696000001",
"studentName": "Sarah",
"_id": "51ed51defcb4cc3696000011",
"__v": 0,
"date": "2013-07-22T15:38:06.259Z",
"numberOfAttemptsBeforeSolved": 2
}
Entry D
{
"problem": "circle",
"courseLesson": "elementary_one, 1",
"studentId": "51ed51d0fcb4cc3696000001",
"studentName": "Sarah",
"_id": "51ed51defcb4cc3696000011",
"__v": 0,
"date": "2013-07-27T15:38:06.259Z",
"numberOfAttemptsBeforeSolved": 4
}
var ProficiencySchema = new Schema({
problem: String
, numberOfAttemptsBeforeSolved: {type: Number, default: 0}
//refers to which lesson, e.g. elementary_one, 2 refers to lesson 2 of elementary_one
, courseLesson: String
, date: {type: Date, default: Date.now}
, studentId: Schema.Types.ObjectId
, studentName: String
})
The best way to do this would be to sort the results in descending date-time order (so the latest response is first) and then to limit the result set by one. This would look something like:
db.proficiencies.find(YOUR QUERY).sort({'date': -1}).limit(1)