MongoDB : How to search based on two Parameters in Mongo - mongodb

I have a Collection named as Orders in my Mongo DB .
Is it possible to do a search on mongo DB based on two fileds .
For example i want to search the collection based on symbol and hi
db.Orders.find({"symbol" : "AADI"})
Please let me know how can i include the other parameter hi also in the search ??
Thanks

Just have two conditions separated by commas:
e.g.
db.users.find(
{ status: "A",
age: 50 }
)
http://docs.mongodb.org/manual/reference/sql-comparison/

Mongodb provides an implicit AND , so when you do
db.inventory.find( { price: 1.99, qty: { $lt: 20 } , sale: true } )
it is same as
db.inventory.find({ $and: [ { price: 1.99 }, { qty: { $lt: 20 } }, { sale: true } ] } )
For other operators you can have a look at the reference
mixing $or with logical AND
db.inventory.find( { price:1.99, $or: [ { qty: { $lt: 20 } }, { sale: true } ] } )
This query will select all documents in the inventory collection where:
the price field value equals 1.99 and
either the qty field value is less than 20 or the sale field value is true.
Other operators
You can refer to the reference for examples to other operators.

Also, once you use:
db.users.find(
{ status: "A",
age: 50 }).pretty()
Using pretty() method at the end of the statement, you make sure that the info comes with a \n per key : value

Related

Mongo filter documents by array of objects

I have to filter candidate documents by an array of objects.
In the documents I have the following fields:
skills = [
{ _id: 'blablabla', skill: 'Angular', level: 3 },
{ _id: 'blablabla', skill: 'React', level: 2 },
{ _id: 'blablabla', skill: 'Vue', level: 4 },
];
When I make the request I get other array of skills, for example:
skills = [
{ skill: 'React', level: 2 },
];
So I need to build a query to get the documents that contains this skill and a greater or equal level.
I try doing the following:
const conditions = {
$elemMatch: {
skill: { $in: skills.map(item => item.skill) },
level: { $gte: { $in: skills.map(item => item.level) } }
}
};
Candidate.find(conditions)...
The first one seems like works but the second one doesn't work.
Any idea?
Thank you in advance!
There are so many problems with this query...
First of all item.tech - it had to be item.skill.
Next, $gte ... $in makes very little sense. $gte means >=, greater or equal than something. If you compare numbers, the "something" must be a number. Like 3 >= 5 resolves to false, and 3 >= 1 resolves to true. 3 >= [1,2,3,4,5] makes no sense since it resolves to true to the first 3 elements, and to false to the last 2.
Finally, $elemMatch doesn't work this way. It tests each element of the array for all conditions to match. What you was trying to write was like : find a document where skills array has a subdocument with skill matching at least one of [array of skills] and level is greater than ... something. Even if the $gte condition was correct, the combination of $elementMatch and $in inside doesen't do any better than regular $in:
{
skill: { $in: skills.map(item => item.tech) },
level: { $gte: ??? }
}
If you want to find candidates with tech skills of particular level or higher, it should be $or condition for each skill-level pair:
const conditions = {$or:
skills.map(s=>(
{skill: { $elemMatch: {
skill:s.skill,
level:{ $gte:s.level }
} } }
))
};

Can a MongoDB query with $or be a covered query?

I want to use an index for my query without retrieving documents ("covered query"), and my query has an $or. Is this possible?
There isn't anything in the documentation I've read to make me think this is impossible, yet my empirical testing suggests otherwise:
> db.inventory.createIndex( { quantity: 1 } )
> db.inventory.createIndex( { price: 1 } )
> db.inventory.insert({quantity:5, price: 10})
> db.inventory.insert({quantity:4, price: 20})
> db.inventory.insert({quantity:50, price: 5})
> db.inventory.find( { $or: [ { quantity: { $lt: 20 } }, { price: 5 } ] }, {_id:0,quantity:1} ).explain({verbose: "executionSummary"})["executionStats"]["totalDocsExamined"]
3
The full execution stats shows something like: PROJECTION < FETCH < OR < [IXSCAN (quantity_1), IXSCAN (price_1)]
A covered query would have 0 documents examined.
Are $or queries are really not supported as covered queries? If they aren't, can I restructure my query in a way that would be supported? Or do I need to submit a separate query for each of the $or clauses?
Let's consider a simpler query:
db.inventory.find( { $or: [ { quantity: 20 }, { price: 5 } ] }, {_id:0,price:1} ).explain({verbose: "executionSummary"})
This query is supposed to return the price for all of the documents where quantity is 20. But, you are also asking it to use the quantity index to match the documents where quantity is 20. How is it supposed to obtain the price for the documents where quantity is 20, only using the quantity index?

Select data where the range between two different fields contains a given number

I want to make a find query on my database for documents that have an input value between or equal to these 2 fields, LOC_CEP_INI and LOC_CEP_FIM
Example: user input a number to the system with value : 69923994, then I use this input to search my database for all documents that have this value between the range of the fields LOC_CEP_INI and LOC_CEP_FIM.
One of my documents (in this example this document is selected by the query because the input is inside the range):
{
"_id" : ObjectId("570d57de457405a61b183ac6"),
"LOC_CEP_FIM" : 69923999, //this field is number
"LOC_CEP_INI" : 69900001, // this field is number
"LOC_NO" : "RIO BRANCO",
"LOC_NU" : "00000016",
"MUN_NU" : "1200401",
"UFE_SG" : "AC",
"create_date" : ISODate("2016-04-12T20:17:34.397Z"),
"__v" : 0
}
db.collection.find( { field: { $gt: value1, $lt: value2 } } );
https://docs.mongodb.com/v3.2/reference/method/db.collection.find/
refer this mongo provide range facility with $gt and $lt .
You have to invert your field names and query value.
db.zipcodes.find({
LOC_CEP_INI: {$gte: 69923997},
LOC_CEP_FIM: {$lte: 69923997}
});
For your query example to work, you would need your documents to hold an array property, and that each item in this prop hold a 69923997 prop. Mongo would then check that this 69923997 prop has a value that is both between "LOC_CEP_INI" and "LOC_CEP_FIM" for each item in your array prop.
Also I'm not sure whether you want LOC_CEP_INI <= 69923997 <= LOC_CEP_FIM or the contrary, so you might need to switch the $gte and $lte conditions.
db.zipcodes.find( {
"LOC_CEP_INI": { "$lte": 69900002 },
"LOC_CEP_FIM": { "$gte": 69900002 } })
Here is the logic use it as per the need:
Userdb.aggregate([
{ "$match": { _id: ObjectId(session._id)}},
{ $project: {
checkout_list: {
$filter: {
input: "$checkout_list",
as: "checkout_list",
cond: {
$and: [
{ $gte: [ "$$checkout_list.createdAt", new Date(date1) ] },
{ $lt: [ "$$checkout_list.createdAt", new Date(date2) ] }
]
}
}
}
}
}
Here i use filter, because of some reason data query on nested data is not gets succeed in mongodb

MongoDB: Modify a field from a document using a function

The documents in my collection have the following format:
{ word: 'apple', number: 5 }
I want to increment the value of number from a javascript function. Yes, I know you can do that with a simple upsert, but I'm planning to do this for arrays and more complicated decisions that can't expressed by operators in a single upsert. This is just a simplified example.
What I've tried so far:
db.a.find({word:'test'})
{ "_id" : ObjectId("53c98ff18b95662af1148ad7"), "word" : "test", "number" : 5 }
db.a.find({word:'test'}).forEach(function(entry) {
inc: entry.number, 5;
print("test", entry.number);
})
test 5
(but it should be 10)
Could you please tell me what am I doing wrong?
db.runCommand({
findAndModify: "people",
query: { name: "Andy" },
sort: { rating: 1 },
update: { $inc: { score: 1 } },
upsert: true
})
As per my comment above. This should work in bulk operations as opposed to an update on each foreach iteration.

MongoDB $gt/$lt operators with prices stored as strings

I'm trying to query my database for prices greater than/less than a user specified number. In my database, prices are stored like so:
{price: "300.00"}
According to the docs, this should work:
db.products.find({price: {$gt:30.00}}).pretty()
But I get no results returned. I've also tried {price: {$gt:30}}.
What am I missing here?
It it because the prices are stored as a string rather than a number in the DB? Is there a way around this?
If you intend to use $gt with strings, you will have to use regex, which is not great in terms of performance. It is easier to just create a new field which holds the number value of price or change this field type to int/double. A javascript version should also work, like so:
db.products.find("this.price > 30.00")
as js will convert it to number before use. However, indexes won't work on this query.
$gt is an operator that can work on any type:
db.so.drop();
db.so.insert( { name: "Derick" } );
db.so.insert( { name: "Jayz" } );
db.so.find( { name: { $gt: "Fred" } } );
Returns:
{ "_id" : ObjectId("51ffbe6c16473d7b84172d58"), "name" : "Jayz" }
If you want to compare against a number with $gt or $lt, then the value in your document also needs to be a number. Types in MongoDB are strict and do not auto-convert like they f.e. would do in PHP. In order to solve your issue, make sure you store the prices as numbers (floats or ints):
db.so.drop();
db.so.insert( { price: 50.40 } );
db.so.insert( { price: 29.99 } );
db.so.find( { price: { $gt: 30 } } );
Returns:
{ "_id" : ObjectId("51ffbf2016473d7b84172d5b"), "price" : 50.4 }
Starting Mongo 4.0, there is a new $toDouble aggregation operator which converts from various types to double (in this case from a string):
// { price: "300.00" }
// { price: "4.2" }
db.collection.find({ $expr: { $gt: [{ $toDouble: "$price" }, 30] } })
// { price: "300.00" }
If you have newer version of mongodb then you can do this:
$expr: {
$gt: [
{ $convert: { input: '$price', to: 'decimal' } },
{ $convert: { input: '0.0', to: 'decimal' } }
]
}
$expr operator: https://docs.mongodb.com/manual/reference/operator/query/expr/
$convert opetator: https://docs.mongodb.com/manual/reference/operator/aggregation/convert/index.html
Alternatively you can convert the values to Int, as per:
http://www.quora.com/How-can-I-change-a-field-type-from-String-to-Integer-in-mongodb
var convert = function(document){
var intValue = parseInt(document.field, 10);
db.collection.update(
{_id:document._id},
{$set: {field: intValue}}
);
}
db.collection.find({field: {$type:2}},{field:1}).forEach(convert)