Good time of day, Habr. This topic is a continuation of a cycle of articles based on materials from the online course M101 from 10gen. Since the second week is one of the most intense, it will be divided into two articles.
Immediately clarify - described in the article is valid for mongo version 2.6. In any case, I recommend to read
off. documentationand if you have free time to
watch coursesThe first article of the cycle')
In this post we will look at CRUD operations. Examples are given on js for the built-in shell and due to the triviality to other languages as in the first article, the examples were not ported.
Mongo provides a complete set of methods for performing CRUD operations.

All CRUD methods in Mongo-drivers are functions (methods) of their programming languages, and not a means for creating expressions of a separate language (hi sql). MongoDb has a special TCP-based protocol for transferring method calls and returning the results of their work.
For example, requesting in the shell
db.users.findOne({name:"Alice"})
We refer to the link to the database object, request its users attribute and call its findOne method (from the collection interface) to which we pass the object that constitutes the search criteria
We constantly work with objects and their methods, not with sql strings.Shell MongoDb is an interactive JS interpreter with a built-in driver. At the entrance, we display information about the version and the name of the current database. It is worth paying attention to this information in order to prevent actions with a non-target base, and monitoring the freshness of the version is superfluous. Any version of the shell can be used with any version of the Mongo server, but some fresh features, the old version of the shell may not be supported.
Since the shell is an interpreter, we can use various valid js constructions to facilitate our work.
Here is a small example often used at the design stage - clears all collections without deleting indexes.
var list=db.getCollectionNames(); for (var i = 0; i < list.length; i++) { if (list[i]!="system.indexes") db.getCollection(list[i]).remove(); }
Shell has several handy features familiar to most linux users.
Arrow Up /
Arrow down - scroll through the history of commands
ctrl + A /
Home - go to the beginning of the line
ctrl + E /
End - go to the end of the line
Ctrl + B /
Arrow left - move the cursor to the left
ctrl + F /
Arrow right - move the cursor to the right
Tab Auto-compile function names and collection names.
To better understand what is happening with our requests - it is worthwhile to tell more about the internal presentation of data in Mongo.
Mongo uses the BSON format (an acronym for Binary JSON). With the detailed specification, you can find on the website
bsonspec.org . When creating a request, the driver encodes the request objects (sample criteria for example), into BSON, and when processing the response it performs the opposite operation.
Depending on the programming language used, the data is mapped to entities of the language that can display them.
- Js- Object
- Python - lists, dictionaries
- Php - arrays
The main thing is that we can take such an entity, and save it in the database. Mongo uses the binary representation of this data.
The BSON format supports the same data types as JSON + plus several types for internal use.
Drivers in one way or another, support all types used in BSON and the data of the language used is reduced to one of the supported types. This should be taken into account when working with languages that have a limited set of types.
All normal collections I have the attribute _id - a unique primary key, about the abnormal collection, we will talk later. It can not be changed - except by deleting the document and inserting a new one.
If _id was not explicitly specified when creating an object, it is formed using a rather tricky algorithm, using additional values that increase entropy
+ + + , .
In some cases, it is more convenient to explicitly define _id explicitly, for example, for a collection that stores user data — you can use a user login as an identifier. For the identifier, you can use any of the supported data types.
In the previous article we have already considered the creation of new documents in the collection. Now consider how to take them back.
There is a find () method for fetching. In cases when we need only one collection item, it is convenient to use findOne ().
findOne(criteria,fields)
criteria - . ( ).
fields - , , - . - true
The second document has one feature — the _id field is always returned, unless it was explicitly stated that it should not be returned.
As they say - better to see once than hear a hundred times
// > db.users.insert({name:"Woody","role":"sheriff",age:"unknown"}) > db.users.insert({name:"Buzz","role":"space ranger",age:"unknown"}) // , name. . - > db.users.findOne({name:"Woody"}) { "_id" : ObjectId("509ffa90cc922c3538cd1ce1"), "name" : "Woody", "role" : "sheriff", "age" : "unknown" } // > db.users.findOne({name:"Woody"}, {name:true}) { "_id" : ObjectId("509ffa90cc922c3538cd1ce1"), "name" : "Woody" } // , , - . , // , . // , > db.users.findOne({name:"Woody"},{name:1,role:1,_id:0}) { "name" : "Woody", "role" : "sheriff" } >
Let's work with find () and consider the operators used to compile complex search criteria.
By the way, I have not forgotten yet - if you receive a large data set, a limited part of them is displayed in the shell (by default 20) and you can enter it for the next part. The fact is that the driver (and not only in the shell). In response to the request does not receive any data. He gets a cursor on them. The cursor is stored on the server for some time (10 minutes by default), then deleted.
The request will actually be executed only when we start reading from the cursor. Then we get the data. Prior to this, no action occurs.
The parameters for find () are exactly the same as for findOne
find(criteria,fields)
We have already considered the case of equivalence search. To compile more complex conditions, the key specifies a document with comparison methods and parameters for them.
$ gt -, more
$ gte - more or equal
$ lt - less
$ lte - less than or equal to
This will look like a query in the shell, for a sample of all users older than 20 but younger than 30 years, with a balance of 100
db.users.find({age:{$gt:20,$lt:30},balance:{$gte:100}});
As you can see, the number of keys in the document-criteria is arbitrary.
Non-equivalent comparison operators can also be applied to strings.
db.people.find({name:{$lt:"D"}})
Mongo knows nothing about locales - utf character codes are compared. It is important not to forget that since Mongo is without a circuit, the same key in different documents of the same collection can contain data of different types. The comparison operations in Mongo are typed. So if we add a document with a name int to our collection, the search query above will not return it in the search results. In general, storing data of different types in the same key is possible, although it is not recommended, since this complicates the selection.
Sorting and comparison operators are case sensitive.
The order of use of comparison operators is not important.Mongo allows you to create queries based not only on the values stored in the document, but also on its structure and data types.
db.people.find({hobby:{$exists:true}})
$ exists - the existence of a document element
You can create a query based on the type of a specific document element.
$ type - BSON type equivalence checking of the specified element
db.people.find({name:{$type:2}})
$ regex - check item for compliance with the specified PCRE
We'll talk more about regexp next week when we look at performance issues. It is worth noting that they do not need to reduce the speed, for example, the search by regex ^ A is transliterated by the engine into a request by the range [A, B)
Let's see how you can make a condition OR
To combine several conditions using a logical OR, use the prefix operator $ or
$ or: [array of conditions]
db.users.find({$or:[{age:{$gt:10}},{name:{$regex:"^A"}}]});
It is worth noting that in compiling more complex queries in the shell, the usefulness of the built-in highlighting of the borders of the elements increases.
For logical conjunction, the $ and operator is used. It is absolutely identical to $ or syntax, and I don’t see any reason to dwell on it in more detail. It is worth noting that this operator is rarely used, since usually the request can be expressed more simply.
Work with arrays
In queries on arrays, mongo shows polymorphism.
db.users.find({favorites:"beer"})
If the favorites document contains a string, then it will be sampled for equivalence; if the favorites array is, then it will be included in the selection if at least one of the elements is equivalent.
This behavior is very common in Mongo idiom.
Mongo does not recursively iterate through the array, only the top level is visible.
There are also several specific operators for searching by arrays.
$ all - selects elements containing all the listed values in the array
$db.users.find(favorites:{$all:{"beer","milk"}})
$ in is an analogue of the Squiel operator IN. Returns all documents the value of the selected item which is listed in the array. A query using this operator can always be replaced by a query with $ or
Dot notation
In the previous examples, we worked with documents containing strings, numbers, and arrays. It's time to get started in the piled objects.
Mongo supports a special syntax that allows you to build queries on the internal elements of the attached documents.
db.users.find("email.work":{$regex:"mail.ru$"}})
Purpose dot notation view the elements of attached documents. This syntax can also be used to access a specific element of an array.
To be continued ...