Preamble
The easiest way to get the database content is to use the find function. The action of this function is largely similar to the usual SELECT * FROM Table query, which extracts all strings. For example, we can use db.users.find() command to extract all documents from the user’s collection created in a previous topic.
Database sample
We can add a call to the pretty() method to display the documents in a more user-friendly visual presentation:
db.users.find().pretty()
However, what if we need to get not all the documents, but only those that meet a certain requirement. For example, we have previously added the following documents to the database:
db.users.insertOne({"name": "Tom", "age": 28, languages: ["english", "spanish"]})
> db.users.insertOne({"name": "Bill", "age": 32, languages: ["english", "french"]})
> db.users.insertOne({"name": "Tom", "age": 32, languages: ["english", "german"]})
Print all documents with name=Tom:
db.users.find({name: "Tom"})
This query will show us two documents with name=Tom.
Now a more complex query: we need to print those objects where name=Tom and age=32 at the same time. That is, in SQL it could look like this: SELECT * FROM Table WHERE Name=’Tom’ AND Age=32. We have the last object added to meet this criterion. Then we can write the next query:
db.users.find({name: "Tom", age: 32})
It’s also easy to find by an element in the array. For example, the next query displays all documents that have English in the array:
db.users.find({languages: "english"})
Let’s complicate the query and get those documents which have two languages in the languages array: “english” and “german” at the same time:
db.users.find({languages: ["english", "german"]})
Now let’s print all the documents where “english” in the languages array comes first:
db.users.find({"languages.0": "english"})
Correspondingly, if we need to print documents where english comes second (e.g. [“german”, “english”]), then instead of zero we put one: languages.1.
MongoDB Projection
A document can have many fields, but not all of these fields may be necessary or important for us when we make a request. And in this case, we can include only the required fields in the sample using the projection.
For example, we can display only a portion of information, for example, the values of “age” fields in all documents where name=Tom:
db.users.find({name: "Tom"}, {age: 1})
Using a unit as the parameter {age: 1} indicates that the query should return only the content of the age property.
And the opposite situation: we want to find all fields in the document except the age property. In this case, we specify 0 as a parameter:
db.persons.find({name: "Tom"}, {age: 0})
Note that even if we note that we only want the name field, the _id field will also be included in the resulting sample. So, if we don’t want to see this field in the sample, we have to explicitly specify it: {“_id”:0}
Alternatively, instead of 1 and 0, we can use true and false:
db.users.find({name: "Tom"}, {age: true, _id: false})
If we don’t want to concretize the sample but want to print all documents, we can leave the first curly brackets empty:
db.users.find({}, {age: 1, _id: 0})
Request to nested objects
Previous requests have been applied to simple objects. But documents can be very complex in structure. For example, let’s add the following document to the collection:
db.users.insert({"name": "Alex", "age": 28, company: {"name": "microsoft", "country": "USA"}})
The nested object with the company key is defined here. And in order to find all documents which have the nested property name=microsoft in their company key, we need to use the point operator:
db.users.find({"company.name": "microsoft"})
MongoDB: Database sample
MongoDB provides a great opportunity to create requests using JavaScript language. For example, let’s create a query that returns those documents where name=Tom. To do this, the function is declared first:
fn = function() { return this.name=="Tom"; }
> db.users.find(fn)
This query is equivalent to the following:
db.users.find("this.name=='Tom'")
The scope of application of JavaScript in the mongo console is not limited to requests only. For example, we can create some function and apply it:
function sqrt(n) { return n*n; }
> sqrt(5)
25
Use of regular expressions
Another great feature when building queries is the use of regular expressions. For example, we will find all documents where the value of the key name begins with the letter T:
db.users.find({name:/Tw+/i})
Setting up queries and sorting
MongoDB presents a number of functions that help to manage the selection from the database. One of them is the limit function. It sets the maximum allowed number of documents to be received. The number is transmitted as a numeric parameter. For example, limit the sampling to three documents:
db.users.find().limit(3)
In this case, we will get the first three documents (if there are 3 or more documents in the collection). But what if we want to sample not first, but by missing a certain number of documents? The skip function will help us to do that. For example, we will skip the first three entries:
db.users.find().skip(3)
MongoDB provides an opportunity to sort the data set received from the database using the sort function. Bypassing values of 1 or -1 to this function, we can specify in which order to sort: in ascending (1) or descending (-1). In many ways, this function is similar to the ORDER BY expression in SQL. For example, sorting in ascending order by field name:
db.users.find().sort({name: 1})
And at the end it should be noted that we can combine all these functions in one chain:
db.users.find().sort({name: 1}).skip(3).limit(3)
Search for a single document
If all documents are retrieved with the find function, the single document is retrieved with the findOne function. Its action is the same as if we used the limit(1) function, which also extracts the first document of the collection. And the combination of the skip and limit functions will extract the document at the desired location.
The $natural parameter
If we suddenly need to sort a limited collection, we can use the $natural parameter. This parameter allows us to specify the sorting: documents are passed in the order they were added to the collection, or in reverse order.
For example, we will select the last five documents:
db.users.find().sort({ $natural: -1 }).limit(5)
Operator $slice
$slice is in some way a combination of limit and skips functions. But unlike them, $slice can work with arrays.
The $slice operator accepts two parameters. The first parameter indicates the total number of documents to be returned. The second parameter is optional, but if it is used, then the first parameter indicates an offset from the beginning (like the skip function), and the second parameter indicates a limit on the number of documents to be retrieved.
For example, each document has an array of languages to store the languages spoken by the person. There can be 1, and 2, and 3 or more. And let’s say that we added the following object earlier:
db.users.insert({"name": "Tom", "age": "32", languages: ["english", "german"]})
And we want to make it so that only one language from the languages array gets into the sample instead of the whole array:
db.users.find ({name: "Tom"}, {languages: {$slice : 1}})
This query, when extracting a document, will leave only the first language in the languages array, i.e. in this case English.
The opposite situation: we need to leave one element in the array as well, but not from the beginning but from the end. In this case, we have to pass a negative value to the parameter:
db.users.find ({name: "Tom"}, {languages: {$slice : -1}});
Now the array will be german since it is the first one at the end of the added element.
We use two parameters at once:
db.users.find ({name: "Tom"}, {languages: {$slice : [-1, 1]}});
The first parameter tells you to start sampling the elements at the end (since it is a negative value), and the second parameter indicates the number of elements to be returned in the array. The result will be “german” in the language array.
Cursors
The result of a sample obtained by using the find function is called a cursor:
var cursor = db.users.find(); null;
To get the cursor and not to output all the data it contains immediately, after the find() method, adds null through a semicolon;
The cursors encapsulate sets of objects derived from the database. Using javascript syntax and cursor methods, we can display the resulting documents on the screen and process them somehow. For example:
var cursor = db.users.find();null;
> while(cursor.hasNext()){
... obj = cursor.next();
... print(obj["name"]);
... }
The cursor has the hasNext method, which shows if there is still a document in the set when searching. And the next method retrieves the current document and moves the cursor to the next document in the set. The result is a document in the obj variable, to which we can access the fields.
Alternatively, we can use the javascript iterator construction – forEach – to iterate through documents in the cursor:
var cursor = db.users.find()
> cursor.forEach(function(obj){
... print(obj.name);
... })
To limit the sample size, the limit method is used, which accepts the number of documents:
var cursor = db.users.find();null;
null
> cursor.limit(5);null;
null
> cursor.forEach(function(obj){
... print(obj.name);
... })
Using the sort() method, you can sort documents with the cursor:
var cursor = db.users.find();null;
null
> cursor.sort({name:1});null;
null
> cursor.forEach(function(obj){
... print(obj.name);
... })
The cursor.sort({name:1}) expression sorts documents in the cursor by a field name in ascending order. If we want to sort in descending order, we use -1: cursor.sort({name:-1}) instead of 1.
And one more skip() method allows to skip a certain number of documents when sampling:
var cursor = db.users.find();null;
null
> cursor.skip(2);null;
null
> cursor.forEach(function(obj){
... print(obj.name);
... })
In this case, we skip two documents.
And besides, you can combine all these methods into chains:
var cursor = db.users.find();null;
null
> cursor.sort({name:1}).limit(3).skip(2);null;
null
> cursor.forEach(function(obj){
... print(obj.name);
... })
MongoDB Tutorial – Modeling with MongoDB
The views expressed on this blog are those of the author and do not necessarily reflect the opinions of Enteros Inc. This blog may contain links to the content of third-party sites. By providing such links, Enteros Inc. does not adopt, guarantee, approve, or endorse the information, views, or products available on such sites.
Are you interested in writing for Enteros’ Blog? Please send us a pitch!
RELATED POSTS
Revolutionizing Cost Allocation and Attribution in Real Estate with Enteros: Optimizing Database Performance for Better Financial Insights
- 24 December 2024
- Database Performance Management
In the fast-evolving world of finance, where banking and insurance sectors rely on massive data streams for real-time decisions, efficient anomaly man…
Enteros: Streamlining Root Cause Analysis and Shared Cost Optimization with Cloud FinOps in the Public Sector
In the fast-evolving world of finance, where banking and insurance sectors rely on massive data streams for real-time decisions, efficient anomaly man…
Optimizing Database Performance with Enteros: Leveraging Cloud FinOps and Observability for the Financial Sector
- 23 December 2024
- Database Performance Management
In the fast-evolving world of finance, where banking and insurance sectors rely on massive data streams for real-time decisions, efficient anomaly man…
Enteros: Enhancing Database Security Cost Management with RevOps and AIOps for the Insurance Sector
In the fast-evolving world of finance, where banking and insurance sectors rely on massive data streams for real-time decisions, efficient anomaly man…