Grokking MongoDB
Vote

0% completed

​

Database, Collection, and Document

Creating a Database

Database Names

What Databases Separate

Creating a Collection

Collection Names

Adding Documents

What a Document Can Contain

Field Names

Reading, Updating and Deleting

Removing Collections and Databases

Data in MongoDB is organized at three levels. A single record, such as one user with a name and an age, is stored as a set of field names and values, and that record is called a document. Documents that belong together, such as all of your users, form a collection. Collections that belong to one application form a database, and one MongoDB server can contain many databases.

If you know relational databases, a collection is similar to a table and a document is similar to a row. The comparison has one limit: rows in a table share the same columns, whereas documents in a collection do not have to share the same fields.

One MongoDB server contains databases, each database contains collections, and each collection contains documents.
One MongoDB server contains databases, each database contains collections, and each collection contains documents.

We will build all three levels for a small list of users, starting from the outermost level. All of the commands run in mongosh, the MongoDB command-line shell.

Creating a Database

The use command selects the database that later commands will work on.

use myDatabase
switched to db myDatabase

The output is misleading in one way, because no database exists yet. MongoDB creates a database only when the first data is stored in it, and show dbs does not list myDatabase at this point. The next command stores a document, and that single insert creates the database, the users collection and the document together.

db.users.insertOne({ name: "John Doe", age: 30, email: "john.doe@example.com" }) show dbs
admin 80.00 KiB config 164.00 KiB local 408.00 KiB myDatabase 8.00 KiB

The sizes on your server will differ. MongoDB uses the admin, config and local databases for its own data, so do not store application data in them.

Automatic creation is convenient, but it has a cost. If you type use myDatabse by mistake, your next insert creates a second database without any warning, and your application may then read from one database and write to the other.

Database Names

A database name has to follow these rules:

  • It cannot be empty, and it must be shorter than 64 bytes. MongoDB stores names as UTF-8, a text encoding in which one character can use more than one byte, so a name of 40 é characters takes 80 bytes and the server rejects it.
  • On Unix and Linux systems, it cannot contain /, \, ., ", $, a space or the null character (the byte with value zero).
  • On Windows, it also cannot contain *, <, >, :, | or ?.
  • It cannot differ from an existing name only by case. If myDatabase exists, the server refuses to create MyDatabase.

What Databases Separate

Each database has its own collections, and a user can be given access to one database and not to another. Databases on the same server are not fully independent, however. They share the memory and disks of that server, and the server configuration applies to all of them. User accounts are also stored together in the admin database, even when an account was created for another database.

Creating a Collection

The users collection already exists, because the insert created it. You need to create a collection explicitly only when you want to set options at creation time, such as validation rules or a maximum size. Without options, the command looks like this:

db.createCollection("orders") show collections
orders users

Collection Names

A collection name should begin with a letter or an underscore. It cannot be empty, cannot contain $, .system. or the null character, and cannot begin with system., because that prefix is reserved for internal collections.

The length limit applies to the full name, which is the database name, a dot and the collection name. That full name can be at most 255 bytes for an unsharded collection, and 235 bytes for a collection split across several servers.

The server does accept a name that starts with a digit, such as 9abc. However, db.9abc.find() is a syntax error in mongosh, and you would have to write db.getCollection("9abc") each time. Collection names are also case sensitive, so users and Users are two separate collections.

Adding Documents

We now add Alice and Bob with insertMany, and then a fourth user who has a phone number and no age or email.

db.users.insertMany([ { name: "Alice", age: 25, email: "alice@example.com" }, { name: "Bob", age: 30, email: "bob@example.com" } ]) db.users.insertOne({ name: "Carol", phone: "555-0100" }) db.users.find()
[ { _id: ObjectId('6ae757149d72706461cb0ce2'), name: 'John Doe', age: 30, email: 'john.doe@example.com' }, { _id: ObjectId('6ae757149d72706461cb0ce3'), name: 'Alice', age: 25, email: 'alice@example.com' }, { _id: ObjectId('6ae757149d72706461cb0ce4'), name: 'Bob', age: 30, email: 'bob@example.com' }, { _id: ObjectId('6ae757149d72706461cb0ce5'), name: 'Carol', phone: '555-0100' } ]

This output shows two things that the insert commands did not.

First, the server accepted Carol even though her fields differ from the others. By default, a collection does not require its documents to share a structure, which makes it easy to add a new field later. The cost is that your application must handle documents where a field is absent. When you need a fixed structure, you can add validation rules to a collection, and MongoDB will then reject documents that break them.

Second, every document gained an _id field that we did not write. Each document must have an _id, and its value must be unique within the collection. If you do not supply one, a generated value is added. You can also supply your own, as long as it is unique and is not an array or a regular expression. After that, the value cannot change. The commands below show both rules. $set, in the last command, gives a field a new value.

db.users.insertOne({ _id: 1, name: "Dana" }) db.users.insertOne({ _id: 1, name: "Erin" }) db.users.updateOne({ _id: 1 }, { $set: { _id: 2 } })
{ acknowledged: true, insertedId: 1 } MongoServerError: E11000 duplicate key error collection: myDatabase.users index: _id_ dup key: { _id: 1 } MongoServerError: Performing an update on the path '_id' would modify the immutable field '_id'

What a Document Can Contain

A document is a set of field and value pairs. Field names are strings, and values can be strings, numbers, arrays, other documents and several other types. MongoDB stores a document in a binary format called BSON, not as text, and one document can be at most 16 mebibytes (16,777,216 bytes).

A value can itself be a document, which lets one record contain related data. To read a field inside it, write the path with a dot:

db.users.insertOne({ name: "Frank", address: { city: "Anytown", zipcode: "12345" } }) db.users.find({ "address.city": "Anytown" })
[ { _id: ObjectId('6ae757159d72706461cb0ce6'), name: 'Frank', address: { city: 'Anytown', zipcode: '12345' } } ]

Field Names

MongoDB has few hard rules for field names. A name cannot contain the null character, it must be unique within its document, and _id is reserved for the identifier described above.

The server does allow . and $ in a field name, but such names cause problems. A query treats a dot as a path, so after you insert { "price.usd": 20 }, the filter { "price.usd": 20 } matches zero documents. It is better to avoid both characters, to choose meaningful names, and to use one naming style across a collection.

Reading, Updating and Deleting

find() with no argument returned every document earlier. A condition limits the result. Here $gt means "greater than", so this command returns John and Bob, both aged 30, and not Alice. Carol, Dana and Frank are not returned either, because they have no age field to compare.

db.users.find({ age: { $gt: 25 } })

An update needs two things: which document to change, and what to change in it. A delete needs only the first.

db.users.updateOne({ name: "John Doe" }, { $set: { age: 31 } }) db.users.deleteOne({ name: "John Doe" })
{ acknowledged: true, insertedId: null, matchedCount: 1, modifiedCount: 1, upsertedCount: 0 } { acknowledged: true, deletedCount: 1 }

A write to a single document is atomic, meaning that all of its changes take effect or none of them do. If one update sets several fields in John's document, no reader will ever see some of the fields changed and others not. This also applies to the documents nested inside his document.

Removing Collections and Databases

drop() removes a collection with all of its documents, and show collections confirms the result:

db.orders.drop() show collections
users

db.dropDatabase() removes the database that is currently selected, with all of its collections. It does not ask for confirmation, and running db.getName() first shows you which database that is.

db.dropDatabase()
{ ok: 1, dropped: 'myDatabase' }

Reading Progress

0%


Vote for new content

On This Page

Creating a Database

Database Names

What Databases Separate

Creating a Collection

Collection Names

Adding Documents

What a Document Can Contain

Field Names

Reading, Updating and Deleting

Removing Collections and Databases