Continuing the Query Documents - I post, let's complete the remaining operations. In previous post, I covered simple queries and querying embedded documents with several kinds of operators that are available in mongodb. In this post, operators related to arrays and evaluation of data are discussed.
Table of Content:
New Document Structure in pokemons collection:
Instead of single weakness, now we will keep an array of weaknesses for a pokemon.
{
name: "pikachu",
type: "Electric",
stats: {
health: 40,
attack: 50,
defense: 45
},
level: 16,
weakness: ["ground", "grass", "dragon"], // now it's array
evolution: "raichu",
moves: [
{name: "quick attack", dmg: 40},
{name: "thunder bolt", dmg: 90},
{name: "irontail", dmg: 50}
]
}
Evaluation Query Operators
There is nothing much to say about evaluation query operators. They just do evaluation.
- $regex (allows you to specify regex expression in your query)
- $text (useful when working with indexes in mongodb, therefore not covered now)
- $jsonSchema (For validating data against a schema)
- $expr
- $mod ( { field: { $mod: [ divisor, remainder ] } })
Usage:
# $regex to find pokemons with "pi" in their name
> db.persons.find({ description: {$regex: /pi/}})
# create a validator when creating collection
# let's create a simple schema for pokemon collection
> db.createCollection( <collection>, { validator: {
required: ["name", "type", "level"],
$jsonSchema: {
name: { bsonType: "string" },
type: { bsonType: "string" },
level: { bsonType: "int", minimum: 1 }
}
}})
# $mod operators helps you perform mod operation on a field against a number
# get all pokemons whose level are divisible by 5
> db.pokemons.find({level: {$mod: [5, 0]}}) # divisor, remainder
$expr : It is related to aggregation. It helps us to use aggregation expressions within the query.
Note: There are some operations for which we need some knowledge of aggregation. Therefore, we will cover the relevant part for now and rest will be covered later.
- Comparing fields: You can use $expr operator to compare two fields. E.g. we can compare level and defense field in our pokemons collection (weird comparision, but will teach you about embedded field)
# get pokemons whose level are greater than their defense
> db.pokemons.find({$expr: {$gt: ["$level", "$stats.defense"] }})
As you can see, you need quotes and
$
sign when specifying the field in$expr
E.g. "$fieldName", "$fieldName.nestedFieldName"
There is another operator $cond
that helps us in creating conditions (if, then, else). We will learn it later in the series.
Querying Arrays
Arrays are here !! Now we will learn how to handle arrays inside documents.
Simple query for an element in array : You can query arrays normally and mongo will take care of the rest. It will check if the value exists in array or not.
# find pokemons with weakness "ground"
> db.pokemons.find({weakness: "ground"})
# if you do something like this, it will check for exact match for array
> db.pokemons.find({weakness: ["ground"]})
Querying an index in array : It is possible to query for a specific index in array. Just specify the index similar to specifying a key in object.
> db.pokemons.find({"weakness.2": "electric" })
What if we have embedded docs inside array?? (Hint: similar to embedded docs)
# find pokemons who have "quick attack" move
> db.pokemons.find({"moves.name": "quick attack"})
This can get tricky when document structure gets more complicated. In our above example, we only looked for a single key. Let's see some more examples that can get us in trouble. We will use a different document structure instead of our pokemons one.
// e.g collection = articles
{
comments: [
{ name: "Nina", rating: 3 },
{ name: "Colt", rating: 4 },
{ name: "Rico", rating: 2.5}
]
}
# find articles where nina's has given rating, greater than 3
# this won't work, it will look for exact match
> db.articles.find({"comments": { name: "Nina", rating: {$gt: 2}}})
# this won't work either
# name can match different comment than the rating
> db.articles.find({"comments.name": "Nina", "comments.rating": {$gt: 2}})
We will solve this problem in later section, where we will learn about operators.
Array Operators
Array operators are few but very useful.
- Operators:
$all
,$size
,$elemMatch
$all : To understand it, let's form a case. Find all pokemons whose weaknesses are ground and electric.
> db.pokemons.find({weakness: {$all: ["ground", "electric"]}})
# Don't try the following query because
# it will look for exact match + order
> db.pokemons.find({weakness: ["ground", "electric"]})
$all
makes sure it finds all elements in array. They can be objects, single values or arrays. It also ignores the order in which you specified elements in query.
$size : Simple...let's you query the size of array.
# find pokemons with 4 moves
> db.pokemons.find({moves: {$size: 4}})
$size operator only accepts exact number. Greater than or less than queries are not possible.
$elemMatch : The operator we need is here !!!...Just kidding. Do you remember the unsolved mystery we just had when querying embedded documents in array ? $elemMatch
can help us with that !! Let's see how
// e.g collection = articles
{
comments: [
{ name: "Nina", rating: 3 },
{ name: "Colt", rating: 4 },
{ name: "Rico", rating: 2.5}
]
}
# find articles where Nina has given a rating greater than 2
> db.articles.find({
comments: {
$elemMatch: {name: "Nina", rating: {$gt: 2}}
}
})
What just happened in that query ??
$elemMatch
helped us in defining how the document should look like, that can match our query. Cool, isn't it ?
So, that was it for querying arrays and embedded docs. If you have any question, feel free to ask in comments. I will try my best to answer them.
Hope you find this useful !
Next Post : Update Documents
Prev Post : Query Documents - Part I
Top comments (0)