Use Queryable Encryption only for query shapes it actually supports, and treat encrypted metadata, storage amplification, and diagnostics as design costs.
Queryable Encryption: Supported Query Patterns, Metadata, Performance, and Schema Planning
AtlasMart must query an encrypted customer identifier without handing plaintext to the database server. Queryable Encryption changes the collection schema, creates auxiliary metadata, and constrains which queries are legal, so schema planning must precede migration.
Learning objectives
Explain how Queryable Encryption differs from deterministic CSFLE and why it requires replica-set or sharded-cluster topology.
Distinguish automatic from explicit QE support across Community, Enterprise Advanced, and Atlas.
Plan encrypted fields around GA equality/range query requirements and identify preview string-query risks.
Identify auxiliary metadata/storage/diagnostic costs before migrating an existing collection.
Use an explicit Community learning path for equality-queryable ciphertext without claiming automatic query analysis.
This lesson pins
MongoDB Community Server 8.3.8 with
mongodb/mongodb-community-server:8.3.8-ubuntu2204-slim, mongosh 2.10.0, and
PyMongo 4.17.0 where driver behavior is used.
Topology: one disposable single-member replica set
rs23 named atlasmart-ch23-l4.
Queryable Encryption requires a replica set or sharded cluster;
a standalone is intentionally not used. Community supports
explicit QE but not automatic QE encryption/query analysis. Host
publication is loopback-only on port 27184.
Authentication/TLS state is stated next to the experiment.
Default read/write concern and primary read preference are used
unless noted.
FCV is observed and never changed. The local
KMS examples generate disposable 96-byte master keys at runtime
and never embed a real cloud/KMIP credential. Atlas, Enterprise
Advanced, AWS KMS, Azure Key Vault, GCP KMS, KMIP, and HSMs are
optional production paths. The one-member replica set is a
learning topology only and provides no production high
availability. Product runtime labs were not executed in the
generation environment; ciphertext values, key identifiers,
timings, storage amplification, and recovery results must be
measured locally rather than copied as invented output.
1. Queryable Encryption is a schema-and-query contract
Queryable Encryption stores sensitive fields as randomized
encrypted values while maintaining encrypted auxiliary state
that lets MongoDB evaluate configured query types without
learning plaintext. The collection must declare an
encryptedFields schema. A field is configured
around its expected query contract; current GA query types are
equality and range. Prefix, suffix, and substring queries are
Public Preview, are explicitly non-production in current
documentation, and can require destructive migration when
preview formats change.
| Query need | Current status | Design implication |
|---|---|---|
| equality on identifier | GA | configure field for equality; evaluate contention/storage |
| numeric/date range | GA | configure range bounds/precision carefully; field cannot simultaneously be equality-configured |
| prefix/suffix/substring string | Public Preview | do not enable in production; preview incompatibility is material |
| arbitrary regex/full text | not a QE substitute | use appropriate search system on data the security model permits |
2. Compatibility is edition + topology + driver + query-analysis component
| Mode | Community 7.0+ replica/sharded | Enterprise/Atlas | Query-analysis component |
|---|---|---|---|
| QE explicit encryption | Yes | Yes | application encrypts each value/query explicitly |
| QE automatic encryption | No | Yes | requires Automatic Encryption Shared Library/query analysis |
| automatic decryption with explicit Community flow | Yes with query analysis bypassed | Yes | driver can decrypt returned ciphertext when configured |
| standalone topology | No | No for QE | use replica set or sharded cluster |
This distinction prevents two common errors: treating “Queryable Encryption supports Community” as meaning Community supports automatic query rewriting, and attempting QE on a standalone because explicit CSFLE worked there.
3. Create a replica-set lab and inspect topology first
docker rm -f atlasmart-ch23-l4 2>/dev/null || truedocker volume rm atlasmart-ch23-l4-db 2>/dev/null || truedocker run -d --name atlasmart-ch23-l4 \ -p 127.0.0.1:27184:27017 \ -v atlasmart-ch23-l4-db:/data/db \ mongodb/mongodb-community-server:8.3.8-ubuntu2204-slim \ --bind_ip_all --port 27017 --replSet rs23until mongosh "mongodb://127.0.0.1:27184/admin" --quiet --eval 'db.runCommand({ping:1}).ok' 2>/dev/null | grep -q 1; do sleep 1; donemongosh "mongodb://127.0.0.1:27184/admin" --quiet --eval ' try { rs.initiate({_id:"rs23",members:[{_id:0,host:"localhost:27017"}]}) } catch(e) { print(e.codeName) }'mongosh "mongodb://127.0.0.1:27184/admin" --quiet --eval ' printjson(db.adminCommand({buildInfo:1})); printjson(db.adminCommand({getParameter:1,featureCompatibilityVersion:1}));' # Wait until PRIMARY before the QE example.until mongosh "mongodb://127.0.0.1:27184/admin?directConnection=true" --quiet --eval 'db.hello().isWritablePrimary' 2>/dev/null | grep -q true; do sleep 1; donepython -m venv /tmp/atlasmart-ch23-qe-venv. /tmp/atlasmart-ch23-qe-venv/bin/activatepython -m pip install --disable-pip-version-check "pymongo[encryption]==4.17.0"python - <<'PY'import os, pathlibp=pathlib.Path('/tmp/atlasmart-ch23-qe-master-key.bin')p.write_bytes(os.urandom(96)); os.chmod(p,0o600); print(p.stat().st_size)PY
4. Explicit equality QE: show schema, ciphertext, and encrypted query value
The following is a Community-compatible learning pattern. It
keeps encryption explicit: the application creates a DEK,
creates the collection with encryptedFields,
encrypts the stored customer reference with the
Indexed QE algorithm, and encrypts the equality
query value with query_type="equality". The server
sees encrypted structures, not plaintext. Exact PyMongo API
details should be rechecked against the installed driver before
production rollout.
from pathlib import Pathfrom bson import Binary, UUID_SUBTYPEfrom bson.codec_options import CodecOptionsfrom pymongo import MongoClientfrom pymongo.encryption import ClientEncryptionURI = "mongodb://127.0.0.1:27184/?directConnection=true"client = MongoClient(URI)key_vault_ns = "encryption.__keyVault"kv = client.encryption.__keyVaultkv.create_index("keyAltNames", unique=True, partialFilterExpression={"keyAltNames":{"$exists":True}})kms = {"local": {"key": Path('/tmp/atlasmart-ch23-qe-master-key.bin').read_bytes()}}ce = ClientEncryption(kms, key_vault_ns, client, CodecOptions())key_id = ce.create_data_key("local", key_alt_names=["atlasmart-qe-customer-ref"])encrypted_fields = { "fields": [{ "keyId": key_id, "path": "customerRef", "bsonType": "string", "queries": {"queryType": "equality", "contention": 8} }]}db = client.atlasmartdb.drop_collection("customers_qe")db.create_collection("customers_qe", encryptedFields=encrypted_fields)coll = db.customers_qevalue = "cust-secret-2304"write_ct = ce.encrypt(value, "Indexed", key_id=key_id, contention_factor=8)coll.insert_one({"customerId":"C-2304", "customerRef":write_ct, "tier":"gold"})query_ct = ce.encrypt(value, "Indexed", key_id=key_id, query_type="equality", contention_factor=8)raw = coll.find_one({"customerRef": query_ct})print('found=', raw is not None)print('stored_type=', type(raw['customerRef']).__name__)print('decrypted=', ce.decrypt(raw['customerRef']))print('encrypted_fields=', db.command('listCollections', filter={'name':'customers_qe'})['cursor']['firstBatch'][0]['options']['encryptedFields'])
A successful local run should show a matching document, an encrypted BSON binary value in the stored field, successful client-side decryption, and collection-level encryptedFields metadata. This generation environment did not run the server/driver lab, so no ciphertext blob, DEK UUID, or storage multiplier is printed as if measured.
5. Range and preview string queries require separate schema decisions
A QE field can be configured for equality or range, not both. Range fields benefit from deliberate min/max bounds and precision choices because broad domains increase metadata and query cost. Current prefix/suffix/substring modes remain Public Preview: they are string-only, have explicit length/query constraints, and current documentation warns that preview data formats will be incompatible with the eventual GA feature. Do not enable them in production merely because the syntax exists.
{ "age": { "bsonType": "int", "queries": {"queryType": "range", "min": 0, "max": 120} }, "nicknamePreview": { "bsonType": "string", "queries": {"queryType": "prefixPreview", "strMinQueryLength": 3, "strMaxLength": 40} }}// Equality and range are GA. prefixPreview/suffixPreview/substringPreview are// Public Preview and are not a production recommendation.
6. Performance, metadata, and observability are part of schema planning
Queryable fields create encrypted metadata and query-processing work. Equality/range options such as contention, range bounds, precision, and trim factors trade write throughput, read cost, leakage resilience, and storage. QE also redacts/omits some diagnostics, so incident response and performance analysis have less plaintext visibility. Build a benchmark with your real value distributions before migration, record index/collection size, insert/update latency distributions, query p95/p99, and recovery behavior, and compare against a non-encrypted control only when the security model permits that test data.
7. Production judgment
Queryable Encryption is not “normal indexing but encrypted.” It is an application/driver/collection/key-management protocol. Decide query shapes first, choose GA query types, plan migration because existing documents are not retroactively encrypted by merely adding a schema, and keep the KMS/key vault available during recovery. Community explicit mode is useful for learning and some application designs, but automatic query analysis remains an Enterprise/Atlas boundary. The next lesson closes the chapter by making key rotation and restore evidence as important as ciphertext creation.
Check your understanding
- Can Queryable Encryption run on a standalone MongoDB server?
- Does Community support QE automatic encryption/query analysis?
- Can one QE field be configured simultaneously for equality and range?
- Are prefix/suffix/substring QE query types production-ready?
- Why measure storage and latency before migration?
Review the answers
1. No. Current compatibility requires MongoDB 7.0+ on a replica set or sharded cluster.
2. No. Community supports explicit QE; automatic encryption/query analysis is an Enterprise/Atlas capability.
3. No. Design the field around one supported query type.
4. No. Current documentation labels them Public Preview and warns about incompatibility with the eventual GA feature.
5. QE auxiliary metadata, cryptographic work, contention/range parameters, and reduced diagnostics can materially change storage and performance.
Authoritative references
Version-, edition-, driver-, topology-, and preview-sensitive encryption behavior was checked against current MongoDB documentation at generation time. Re-check these sources before applying the procedure to a later release.
- MongoDB Encryption
- Configure Encryption at Rest
- Atlas Encryption at Rest
- Client-Side Field Level Encryption
- CSFLE Compatibility
- CSFLE Encryption Schemas
- Queryable Encryption
- Queryable Encryption Compatibility
- Queryable Encryption Features
- Queryable Encryption Supported Operations
- Encrypted Fields and Enabled Queries
- Create an Encryption Schema
- Explicit Queryable Encryption
- Queryable Encryption KMS Providers
- Rotate and Rewrap Encryption Keys
- Key Vault createKey
- Key Vault getKeyVault
- MongoClient Queryable Encryption Options
- PyMongo CSFLE Upgrade Requirements
- MongoDB 8.3 Release Notes
- mongosh Release Notes
- PyMongo Release Notes