This section summarizes how different insert and update operations
handle dollar ($
) prefixed field names. MongoDB discourages the use
of dollar prefixed field names because some features aren't
supported with these fields. See General Restrictions for more information.
Insert Operations
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 }
)
Document Replacing Updates
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
.
Document Modifying Updates
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
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 } }
} )
Updates Using Aggregation Pipelines
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:
db.school.insertOne (
{
"_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" }
] )