$replaceWith (aggregation)
On this page本页内容
Definition定义
$replaceWith
New in version 4.2.4.2版新增。Replaces the input document with the specified document.用指定的文档替换输入文档。The operation replaces all existing fields in the input document, including the该操作将替换输入文档中的所有现有字段,包括_id
field._id
字段。With使用$replaceWith
, you can promote an embedded document to the top-level.$replaceWith
,您可以将嵌入文档提升到顶级文档。You can also specify a new document as the replacement.您也可以指定一个新文档作为替换文档。The$replaceWith
stage performs the same action as the$replaceRoot
stage, but the stages have different forms.$replaceWith
阶段执行与$replaceRoot
阶段相同的操作,但阶段具有不同的形式。The$replaceWith
stage has the following form:$replaceWith
阶段具有以下形式:{ $replaceWith: <replacementDocument> }
The replacement document can be any valid expression that resolves to a document. For more information on expressions, see Expressions.替换文档可以是解析为文档的任何有效表达式。有关表达式的详细信息,请参阅表达式。
Behavior行为
If the 如果<replacementDocument>
is not a document, $replaceWith
errors and fails.<replacementDocument>
不是文档,$replaceWith
将出错并失败。
If the 如果<replacementDocument>
resolves to a missing document (i.e. the document does not exist), $replaceWith
errors and fails. For example, create a collection with the following documents:<replacementDocument>
解析为缺少文档(即文档不存在),$replaceWith
将出错并失败。例如,使用以下文档创建集合:
db.collection.insertMany([
{ "_id": 1, "name" : { "first" : "John", "last" : "Backus" } },
{ "_id": 2, "name" : { "first" : "John", "last" : "McCarthy" } },
{ "_id": 3, "name": { "first" : "Grace", "last" : "Hopper" } },
{ "_id": 4, "firstname": "Ole-Johan", "lastname" : "Dahl" },
])
Then the following 然后,以下$replaceWith
operation fails because one of the document does not have the name
field:$replaceWith
操作失败,因为其中一个文档没有name
字段:
db.collection.aggregate([
{ $replaceWith: "$name" }
])
To avoid the error, you can use 为了避免错误,您可以使用$mergeObjects
to merge the name
document with some default document; $mergeObjects
将name
文档与某些默认文档合并;for example:例如:
db.collection.aggregate([
{ $replaceWith: { $mergeObjects: [ { _id: "$_id", first: "", last: "" }, "$name" ] } }
])
Alternatively, you can skip the documents that are missing the 或者,您可以跳过缺少name
field by including a $match
stage to check for existence of the document field before passing documents to the $replaceWith
stage:name
字段的文档,方法是在将文档传递到$replaceWith
阶段之前,包括$match
阶段以检查文档字段的存在:
db.collection.aggregate([
{ $match: { name : { $exists: true, $not: { $type: "array" }, $type: "object" } } },
{ $replaceWith: "$name" }
])
Or, you can use 或者,您可以使用$ifNull
expression to specify some other document to be root; $ifNull
表达式指定其他文档为根文档;for example:例如:
db.collection.aggregate([
{ $replaceWith: { $ifNull: [ "$name", { _id: "$_id", missingName: true} ] } }
])
Examples实例
$replaceWith
an Embedded Document Field嵌入式文档字段
Create a collection named 使用以下文档创建一个名为people
with the following documents:people
的集合:
db.people.insertMany([
{ "_id" : 1, "name" : "Arlene", "age" : 34, "pets" : { "dogs" : 2, "cats" : 1 } },
{ "_id" : 2, "name" : "Sam", "age" : 41, "pets" : { "cats" : 1, "fish" : 3 } },
{ "_id" : 3, "name" : "Maria", "age" : 25 }
])
The following operation uses the 以下操作使用$replaceWith
stage to replace each input document with the result of a $mergeObjects
operation. $replaceWith
阶段将每个输入文档替换为$mergeObjects
操作的结果。The $mergeObjects
expression merges the specified default document with the pets
document.$mergeObjects
表达式将指定的默认文档与pets
文档合并。
db.people.aggregate( [
{ $replaceWith: { $mergeObjects: [ { dogs: 0, cats: 0, birds: 0, fish: 0 }, "$pets" ] } }
] )
The operation returns the following results:该操作返回以下结果:
{ "dogs" : 2, "cats" : 1, "birds" : 0, "fish" : 0 }
{ "dogs" : 0, "cats" : 1, "birds" : 0, "fish" : 3 }
{ "dogs" : 0, "cats" : 0, "birds" : 0, "fish" : 0 }
$replaceWith
a Document Nested in an Array嵌套在数组中的文档
A collection named 一个名为students
contains the following documents:students
的集合包含以下文档:
db.students.insertMany([
{
"_id" : 1,
"grades" : [
{ "test": 1, "grade" : 80, "mean" : 75, "std" : 6 },
{ "test": 2, "grade" : 85, "mean" : 90, "std" : 4 },
{ "test": 3, "grade" : 95, "mean" : 85, "std" : 6 }
]
},
{
"_id" : 2,
"grades" : [
{ "test": 1, "grade" : 90, "mean" : 75, "std" : 6 },
{ "test": 2, "grade" : 87, "mean" : 90, "std" : 3 },
{ "test": 3, "grade" : 91, "mean" : 85, "std" : 4 }
]
}
])
The following operation promotes the embedded document(s) with the 以下操作将grade
field greater than or equal to 90
to the top level:grade
字段大于或等于90
的嵌入文档提升到最高级别:
db.students.aggregate( [
{ $unwind: "$grades" },
{ $match: { "grades.grade" : { $gte: 90 } } },
{ $replaceWith: "$grades" }
] )
The operation returns the following results:该操作返回以下结果:
{ "test" : 3, "grade" : 95, "mean" : 85, "std" : 6 }
{ "test" : 1, "grade" : 90, "mean" : 75, "std" : 6 }
{ "test" : 3, "grade" : 91, "mean" : 85, "std" : 4 }
$replaceWith
a Newly Created Document新创建的文档
Example 1
An example collection 示例集合sales
is populated with the following documents:sales
由以下文档填充:
db.sales.insertMany([
{ "_id" : 1, "item" : "butter", "price" : 10, "quantity": 2, date: ISODate("2019-03-01T08:00:00Z"), status: "C" },
{ "_id" : 2, "item" : "cream", "price" : 20, "quantity": 1, date: ISODate("2019-03-01T09:00:00Z"), status: "A" },
{ "_id" : 3, "item" : "jam", "price" : 5, "quantity": 10, date: ISODate("2019-03-15T09:00:00Z"), status: "C" },
{ "_id" : 4, "item" : "muffins", "price" : 5, "quantity": 10, date: ISODate("2019-03-15T09:00:00Z"), status: "C" }
])
Assume that for reporting purposes, you want to calculate for each completed sale, the total amount as of the current report run time. 假设出于报告目的,您希望为每个已完成的销售计算截至当前报告运行时的总金额。The following operation finds all the sales with status 以下操作查找状态为C
and creates new documents using the $replaceWith
stage. C
的所有销售,并使用$replaceWith
阶段创建新文档。The $replaceWith
calculates the total amount as well as uses the variable NOW
to get the current time.$replaceWith
计算总额,并使用变量NOW
获取当前时间。
db.sales.aggregate([
{ $match: { status: "C" } },
{ $replaceWith: { _id: "$_id", item: "$item", amount: { $multiply: [ "$price", "$quantity"]}, status: "Complete", asofDate: "$$NOW" } }
])
The operation returns the following documents:该操作返回以下文档:
{ "_id" : 1, "item" : "butter", "amount" : 20, "status" : "Complete", "asofDate" : ISODate("2019-06-03T22:47:54.812Z") }
{ "_id" : 3, "item" : "jam", "amount" : 50, "status" : "Complete", "asofDate" : ISODate("2019-06-03T22:47:54.812Z") }
{ "_id" : 4, "item" : "muffins", "amount" : 50, "status" : "Complete", "asofDate" : ISODate("2019-06-03T22:47:54.812Z") }
Example 2
An example collection 示例集合reportedsales
is populated with the reported sales information by quarter and regions:reportedsales
按季度和地区填充报告的销售信息:
db.reportedsales.insertMany( [
{ _id: 1, quarter: "2019Q1", region: "A", qty: 400 },
{ _id: 2, quarter: "2019Q1", region: "B", qty: 550 },
{ _id: 3, quarter: "2019Q1", region: "C", qty: 1000 },
{ _id: 4, quarter: "2019Q2", region: "A", qty: 660 },
{ _id: 5, quarter: "2019Q2", region: "B", qty: 500 },
{ _id: 6, quarter: "2019Q2", region: "C", qty: 1200 }
] )
Assume that for reporting purposes, you want to view the reported sales data by quarter; e.g.假设出于报告目的,您希望按季度查看报告的销售数据;例如。
{ "_id" : "2019Q1", "A" : 400, "B" : 550, "C" : 1000 }
To view the data grouped by quarter, you can use the following aggregation pipeline:要查看按季度分组的数据,可以使用以下聚合管道:
db.reportedsales.aggregate( [
{ $addFields: { obj: { k: "$region", v: "$qty" } } },
{ $group: { _id: "$quarter", items: { $push: "$obj" } } },
{ $project: { items2: { $concatArrays: [ [ { "k": "_id", "v": "$_id" } ], "$items" ] } } },
{ $replaceWith: { $arrayToObject: "$items2" } }
] )
First stage:第一阶段:-
The$addFields
stage adds a newobj
document field that defines the keyk
as the region value and the valuev
as the quantity for that region.$addFields
阶段添加一个新的obj
文档字段,该字段将键k
定义为区域值,将值v
定义为该区域的数量。For example:例如:{ "_id" : 1, "quarter" : "2019Q1", "region" : "A", "qty" : 400, "obj" : { "k" : "A", "v" : 400 } }
Second stage:第二阶段:-
The$group
stage groups by the quarter and uses$push
to accumulate theobj
fields into a newitems
array field.$group
阶段按季度分组,并使用$push
将obj
字段累积到一个新的items
数组字段中。For example:例如:{ "_id" : "2019Q1", "items" : [ { "k" : "A", "v" : 400 }, { "k" : "B", "v" : 550 }, { "k" : "C", "v" : 1000 } ] }
Third stage:第三阶段:-
The$project
stage uses$concatArrays
to create a new arrayitems2
that includes the_id
info and the elements from theitems
array:$project
阶段使用$concatArrays
创建一个新的数组items2
,其中包括_id
信息和items数组中的元素:{ "_id" : "2019Q1", "items2" : [ { "k" : "_id", "v" : "2019Q1" }, { "k" : "A", "v" : 400 }, { "k" : "B", "v" : 550 }, { "k" : "C", "v" : 1000 } ] }
Fourth stage:第四阶段:-
The$replaceWith
uses the$arrayToObject
to convert theitems2
into a document, using the specified keyk
and valuev
pairs and outputs that document to the next stage.$replaceWith
使用$arrayToObject
将items2
转换为文档,使用指定的键k
和值v
对,并将该文档输出到下一阶段。For example:例如:{ "_id" : "2019Q1", "A" : 400, "B" : 550, "C" : 1000 }
The aggregation returns the following document:聚合返回以下文档:
{ "_id" : "2019Q1", "A" : 400, "B" : 550, "C" : 1000 }
{ "_id" : "2019Q2", "A" : 660, "B" : 500, "C" : 1200 }
$replaceWith
a New Document Created from $$ROOT
and a Default Document$replaceWith
从$$ROOT
创建的新文档和默认文档
$replaceWith
a New Document Created from $$ROOT
and a Default DocumentCreate a collection named 使用以下文档创建名为contacts
with the following documents:contacts
的集合:
db.contacts.insertMany( [
{ "_id" : 1, name: "Fred", email: "fred@example.net" },
{ "_id" : 2, name: "Frank N. Stine", cell: "012-345-9999" },
{ "_id" : 3, name: "Gren Dell", cell: "987-654-3210", email: "beo@example.net" }
] )
The following operation uses 以下操作使用$replaceWith
with $mergeObjects
to output current documents with default values for missing fields:$replaceWith
和$mergeObjects
来输出缺少字段的具有默认值的当前文档:
db.contacts.aggregate( [
{ $replaceWith:
{ $mergeObjects:
[
{ _id: "", name: "", email: "", cell: "", home: "" },
"$$ROOT"
]
}
}
] )
The aggregation returns the following documents:聚合返回以下文档:
{
_id: 1,
name: 'Fred',
email: 'fred@example.net',
cell: '',
home: ''
},
{
_id: 2,
name: 'Frank N. Stine',
email: '',
cell: '012-345-9999',
home: ''
},
{
_id: 3,
name: 'Gren Dell',
email: 'beo@example.net',
cell: '',
home: '987-654-3210'
}