Docs Menu
Docs Home
/
MongoDB Manual
/ / / / /

Encrypted Collections

On this page

  • Overview
  • Metadata Collections
  • Dropping Encrypted Collections
  • Storage Costs
  • Write Costs
  • Insert Operations
  • Update Operations
  • Delete Operations
  • Metadata Collection Compaction
  • Scheduling Metadata Compaction
  • Running Metadata Compaction

Field level encryption comes with performance and storage costs. Every field you choose to encrypt:

  • Adds writes to insert and update operations.

  • Requires additional storage, because MongoDB maintains an index of encrypted fields to improve query performance.

This section lists the writes per operation and explains how to compact encrypted collection indexes so that you can minimize write and storage costs. If you want to encrypt fields and configure them for querying, see Encrypted Fields and Enabled Queries.

Queryable Encryption introduces the ability to encrypt sensitive fields in your documents using randomized encryption, while still being able to query the encrypted fields.

With Queryable Encryption, a given plaintext value always encrypts to a different ciphertext, while still remaining queryable. To enable this functionality, Queryable Encryption uses three data structures:

  • Two metadata collections

  • A field in every document in the encrypted collection called __safeContent__

Important

It is critical that these data structures are not modified or deleted, or query results will be incorrect.

When you create an encrypted collection, MongoDB creates two metadata collections:

  • enxcol_.<collectionName>.esc, referred to as ESC

  • enxcol_.<collectionName>.ecoc, referred to as ECOC

Example

If you create a collection called "patients", MongoDB creates the following metadata collections:

  • enxcol_.patients.esc

  • enxcol_.patients.ecoc

When you insert documents with a queryable encrypted field, MongoDB updates the metadata collections to maintain an index that enables querying. The field becomes an "indexed field". This comes at a cost in storage and write speed for every such field.

When you drop an encrypted collection, drop the associated metadata collections enxcol_.<collectionName>.esc and enxcol_.<collectionName>.ecoc immediately afterwards. Otherwise, re-creating the collection with the same name puts the metadata collections in a conflicted state that consumes excess storage space and degrades CRUD performance.

Storage and write costs increase based on the number of indexed fields per document. Before any metadata compaction, the ESC and ECOC contain one metadata document for every field/value pair of every indexed field, so indexing one encrypted field/value pair across 1000 documents requires 1000 documents in the ESC and 1000 documents in the ECOC.

Important

Expect a Queryable Encryption collection to have 2-3 times the storage requirements of the documents, to account for metadata collections. For example, a 1 GB collection may have a storage requirement of 2-3 GB.

When inserting a document, each indexed field requires two additional writes to metadata collections.

  • One write to ESC

  • One write to ECOC

Example

Inserting a document with two indexed fields requires:

  • One write to the encrypted collection.

  • Four writes to the metadata collections.

When updating a document, each indexed field requires two additional writes to metadata collections.

  • One write to ESC

  • One write to ECOC

Example

Updating a document with two indexed fields requires:

  • One write to the encrypted collection.

  • Four writes to the metadata collections.

When deleting a document, indexed fields do not require any additional writes.

As you insert or update documents, the metadata collections change and grow. Metadata collection compaction empties the ECOC and reduces the size of the ESC.

Important

In the worst case, running metadata compaction reveals the number of unique field/value pairs inserted across all documents since the previous compaction.

For details on the exact information revealed by metadata compaction, see "Section 6: Theoretical Analysis" and "Section 9: Guidelines" in MongoDB's Queryable Encryption Technical Paper.

As a best practice, keep track of the following information:

  • encfields: the number of encrypted fields per document.

  • docinserts: the number of documents inserted since the last compaction.

  • valinserts: the number of unique field/value pairs inserted since the last compaction.

To reduce the size of the ESC metadata collection by at least t documents, run metadata compaction when the following formula is satisfied:

(encfields · docinserts) - valinsertst

The number of encrypted fields per document multiplied by the number of insertions since last compaction, minus the number of unique field/value pairs inserted across all documents since the last compaction, should be greater than or equal to the number of documents to remove from the ESC.

For example, in a collection with six encrypted fields, you can reduce the size of the ESC by at least 1000 documents when total documents inserted and unique field/value pairs inserted since the last compaction meet the following conditions:

(6 · docinserts) - valinserts1000

The formula would be satisfied, for example, if 200 documents were inserted since the last compaction with a total of 200 unique field/value pairs across all documents, or if 400 documents were inserted since the last compaction with 700 unique field/value pairs.

You must run metadata compaction manually. Use mongosh and run the db.collection.compactStructuredEncryptionData() command:

Example

const eDB = "encryption"
const eKV = "__keyVault"
const secretDB = "records"
const secretCollection = "patients"
const localKey = fs.readFileSync("master-key.txt")
const localKeyProvider = { key: localKey }
const queryableEncryptionOpts = {
kmsProviders: { local: localKeyProvider },
keyVaultNamespace: `${eDB}.${eKV}`,
}
const encryptedClient = Mongo("localhost:27017", queryableEncryptionOpts)
const encryptedDB = encryptedClient.getDB(secretDB)
const encryptedCollection = encryptedDB.getCollection(secretCollection)
encryptedCollection.compactStructuredEncryptionData()
{
"stats": {
...
},
"ok": 1,
...
}

You can check the size of a metadata collection using mongosh and running the db.collection.totalSize() command.

Example

In this example, the encrypted collection is named "patients".

db.enxcol_.patients.esc.totalSize()
1407960328

Back

Encrypt Collections at Creation

Next

Explicit Encryption