Docs Menu
Docs Home
/
MongoDB Manual
/ /

Field Names with Periods (.) and Dollar Signs ($)

On this page

  • Overview
  • Insert operations
  • Document Replacing Updates
  • Document Modifying Updates
  • Updates Using Aggregation Pipelines
  • General Restrictions

MongoDB 5.0 adds improved support for field names that are dollar ($) prefixed or that contain periods (.). The validation rules for storing data have been updated to make it easier to work with data sources that use these characters.

In most cases data that has been stored using field names like these is not directly accessible. You need to use helper methods like $getField, $setField, and $literal in queries that access those fields.

The field name validation rules are not the same for all types of storage operations. This page summarizes how different insert and update operations handle dollar ($) prefixed field names.

Dollar ($) prefixed fields are permitted as top level and nested field names for inserts.

db.sales.insertOne( {
"$price": 50.00,
"quantity": 30
} )

Dollar ($) prefixed fields are permitted on inserts using otherwise reserved words. Operator names like $inc can be used as field names as well as words like id, db, and ref.

db.books.insertOne( {
"$id": "h1961-01",
"location": {
"$db": "novels",
"$ref": "2007042768",
"$inc": true
} } )

An update which creates a new document during an upsert is treated as an insert rather than an update for field name validation. Upserts can accept dollar ($) prefixed fields. However, upserts are a special case and similar update operations may cause an error if the match portion of the update selects an existing document.

This code sample has upsert: true so it will insert a new document if the collection doesn't already contain a document that matches the query term, { "date": "2021-07-07" }. If this sample code matches an existing document, the update will fail since $hotel is dollar ($) prefixed.

db.expenses.updateOne(
{ "date": "2021-07-07" },
{ $set: {
"phone": 25.17,
"$hotel": 320.10
} },
{ upsert: true }
)

Update operators either replace existing fields with new documents or else modify those fields. In cases where the update performs a replacement, dollar ($) prefixed fields are not permitted as top level field names.

Consider a document like

{
"_id": "E123",
"address": {
"$number": 123,
"$street": "Elm Road"
},
"$rooms": {
"br": 2,
"bath": 1
}
}

You could use an update operator that replaces an existing document to modify the address.$street field but you could not update the $rooms field that way.

db.housing.updateOne(
{ "_id": "E123" },
{ $set: { "address.$street": "Elm Ave" } }
)

Use $setField as part of an aggregation pipeline to update top level dollar ($) prefixed fields like $rooms.

When an update modifies, rather than replaces, existing document fields, dollar ($) prefixed fields can be top level field names. Subfields can be accessed directly, but you need a helper method to access the top level fields.

Tip

See also:

Consider a collection with documents like this inventory record:

{
_id: ObjectId("610023ad7d58ecda39b8d161"),
"part": "AB305",
"$bin": 200,
"quantity": 100,
"pricing": { sale: true, "$discount": 60 }
}

The pricing.$discount subfield can be queried directly.

db.inventory.findAndModify( {
query: { "part": { $eq: "AB305" } },
update: { $inc: { "pricing.$discount": 10 } }
} )

Use $getField and $literal to access the value of the top level $bin field.

db.inventory.findAndModify( {
query: { $expr: {
$eq: [ { $getField: { $literal: "$bin" } }, 200 ]
} },
update: { $inc: { "quantity": 10 } }
} )

Use $setField, $getField, and $literal in the $replaceWith stage to modify dollar ($) prefixed fields in an aggregation pipeline.

Consider a collection of school records like:

{
"_id": 100001,
"$term": "fall",
"registered": true,
"grade": 4
}

Create a new collection for the spring semester using a pipeline to update the dollar ($) prefixed $term field.

db.school.aggregate( [
{ $match: { "registered": true } },
{ $replaceWith: {
$setField: {
field: { $literal: "$term" },
input: "$$ROOT",
value: "spring"
} } },
{ $out: "spring2022" }
] )

In addition to the storage validation rules above, there are some general restrictions on using dollar ($) prefixed field names. These fields cannot:

  • Be indexed

  • Be used as part of a shard key

  • Be validated using $jsonSchema

  • Be be modified with an escape sequence

  • Be used with Field Level Encryption

  • Be used as a subfield in an _id document

Warning

Possible Data Loss With Dollar Signs ($) and Periods (.)

There is a small chance of data loss when using dollar ($) prefixed field names or field names that contain periods (.) if these field names are used in conjunction with unacknowledged writes (write concern w=0) on servers that are older than MongoDB 5.0.

When running insert, update, and findAndModify commands, drivers that are 5.0 compatible remove restrictions on using documents with field names that are dollar ($) prefixed or that contain periods (.). These field names generated a client-side error in earlier driver versions.

The restrictions are removed regardless of the server version the driver is connected to. If a 5.0 driver sends a document to an older server, the document will be rejected without sending an error.

Warning

Import and Export Concerns With Dollar Signs ($) and Periods (.)

Starting in MongoDB 5.0, document field names can be dollar ($) prefixed and can contain periods (.). However, mongoimport and mongoexport may not work as expected in some situations with field names that make use of these characters.

MongoDB Extended JSON v2 cannot differentiate between type wrappers and fields that happen to have the same name as type wrappers. Do not use Extended JSON formats in contexts where the corresponding BSON representations might include dollar ($) prefixed keys. The DBRef mechanism is an exception to this general rule.

There are also restrictions on using mongoimport and mongoexport with periods (.) in field names. Since CSV files use the period (.) to represent data hierarchies, a period (.) in a field name will be misinterpreted as a level of nesting.

Back

Distributed Queries