定義
$replaceWithReplaces the input document with the specified document. The operation replaces all existing fields in the input document, including the
_idfield. With$replaceWith, you can promote an embedded document to the top-level. You can also specify a new document as the replacement.The
$replaceWithstage performs the same action as the$replaceRootstage, but the stages have different forms.The
$replaceWithstage has the following form:{ $replaceWith: <replacementDocument> } 置換用ドキュメントには、有効な式に変換される任意のドキュメントが利用できます。 式の詳細については、「式 」を参照してください。
動作
If the <replacementDocument> is not a document, $replaceWith errors and fails.
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:
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:
db.collection.aggregate([ { $replaceWith: "$name" } ])
エラーを回避するには、$mergeObjects を使用して name ドキュメントをデフォルトのドキュメントと結合します。次に例を示します。
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:
db.collection.aggregate([ { $match: { name : { $exists: true, $not: { $type: "array" }, $type: "object" } } }, { $replaceWith: "$name" } ])
または、$ifNull 式を使用して、次に挙げるような他のドキュメントをルートに指定しても構いません。
db.collection.aggregate([ { $replaceWith: { $ifNull: [ "$name", { _id: "$_id", missingName: true} ] } } ])
例
$replaceWith 埋め込みドキュメント フィールドの場合
次のドキュメントを含む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. The $mergeObjects expression merges the specified default document with the pets document.
db.people.aggregate( [ { $replaceWith: { $mergeObjects: [ { dogs: 0, cats: 0, birds: 0, fish: 0 }, "$pets" ] } } ] )
この操作は次の結果を返します。
[ { 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 配列にネストされたドキュメントの場合
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 } ] } ])
次の操作では、90 以上の grade フィールドを持つ埋め込みドキュメントが最上位レベルに引き上げられます。
db.students.aggregate( [ { $unwind: "$grades" }, { $match: { "grades.grade" : { $gte: 90 } } }, { $replaceWith: "$grades" } ] )
この操作は次の結果を返します。
[ { 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 新しく作成されたドキュメントの場合
例 1
サンプルコレクション 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. The $replaceWith calculates the total amount as well as uses the variable NOW to get the current time.
db.sales.aggregate([ { $match: { status: "C" } }, { $replaceWith: { _id: "$_id", item: "$item", amount: { $multiply: [ "$price", "$quantity"]}, status: "Complete", asofDate: "$$NOW" } } ])
この操作により、次のドキュメントが返されます。
[ { _id: 1, item: 'butter', amount: 20, status: 'Complete', asofDate: '...' }, { _id: 3, item: 'jam', amount: 50, status: 'Complete', asofDate: '...' }, { _id: 4, item: 'muffins', amount: 50, status: 'Complete', asofDate: '...' } ]
例 2
サンプルコレクション 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 } ] )
レポート作成の目的で、四半期ごとに報告された売上データを表示したいとします。例を以下に示します。
{ "_id" : "2019Q1", "A" : 400, "B" : 550, "C" : 1000 }
四半期ごとにグループ化されたデータを表示するには、次の集計パイプラインを使用できます。
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" } } ] )
- 第 1 ステージ:
$addFieldsステージでは、キーkを地域値として定義し、値vをその地域の数量として定義する新しいobjドキュメント フィールドが追加されます。以下に例を挙げます。{ "_id" : 1, "quarter" : "2019Q1", "region" : "A", "qty" : 400, "obj" : { "k" : "A", "v" : 400 } } - 第 2 ステージ:
$groupステージは四半期ごとにグループ化され、$pushを使用してobjフィールドを新しいitems配列フィールドに累積します。以下に例を挙げます。{ "_id" : "2019Q1", "items" : [ { "k" : "A", "v" : 400 }, { "k" : "B", "v" : 550 }, { "k" : "C", "v" : 1000 } ] } - 第 3 ステージ:
$projectステージでは、$concatArraysを使用して、_id情報とitems配列の要素を含む新しい配列items2を作成します。{ "_id" : "2019Q1", "items2" : [ { "k" : "_id", "v" : "2019Q1" }, { "k" : "A", "v" : 400 }, { "k" : "B", "v" : 550 }, { "k" : "C", "v" : 1000 } ] } - 第 4 ステージ
The
$replaceWithuses the$arrayToObjectto convert theitems2into a document, using the specified keykand valuevpairs and outputs that document to the next stage. For example:{ "_id" : "2019Q1", "A" : 400, "B" : 550, "C" : 1000 }
この集計により、次のドキュメントが返されます。
[ { _id: '2019Q1', A: 400, B: 550, C: 1000 }, { _id: '2019Q2', A: 660, B: 500, C: 1200 } ]
$replaceWith を使用した、$$ROOT とデフォルト ドキュメントから作成した新しいドキュメントへの置換
次のドキュメントを含む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:
db.contacts.aggregate( [ { $replaceWith: { $mergeObjects: [ { _id: "", name: "", email: "", cell: "", home: "" }, "$$ROOT" ] } } ] )
この集計は、次のドキュメントを返します。
[ { _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: '987-654-3210', home: '' } ]
このページのC#の例では、Atlasサンプルデータセット の sample_mflixデータベースを使用します。MongoDB Atlasクラスターを無料で作成して、サンプルデータセットをロードする方法については、 MongoDB .NET/ C#ドライバーのドキュメントの「 開始 」を参照してください。
次の Movie クラスは、sample_mflix.movies コレクション内のドキュメントをモデル化します。
[] public class Movie { [] public ObjectId Id { get; set; } [] public string Title { get; set; } = null!; [] public int? Year { get; set; } [] public int? Runtime { get; set; } [] public string? Rated { get; set; } [] public int Metacritic { get; set; } [] public string? Plot { get; set; } [] public string? Type { get; set; } [] public string[]? Cast { get; set; } [] public string[]? Directors { get; set; } [] public string[]? Writers { get; set; } [] public ImdbData? Imdb { get; set; } }
次の ImdbData クラスは、各 Movie の imdb フィールド内の埋め込みドキュメントをモデル化します。
[] public class ImdbData { [] public int? ImdbId { get; set; } [] public double? Rating { get; set; } [] public int? Votes { get; set; } }
To use the MongoDB .NET/C# driver to add a $replaceWith stage to an aggregation pipeline, call the UnionWith() method on a PipelineDefinition object.
次の例では、タイトルによって Movie ドキュメントをアルファベット順にソートし、結果を 5 つのドキュメントに制限し、各 Movie ドキュメントをその Imdb プロパティに保存されている ImdbData ドキュメントに置き換えるパイプラインステージを作成します。
var pipeline = new EmptyPipelineDefinition<Movie>() .Sort(Builders<Movie>.Sort.Ascending(m => m.Title)) .Limit(5) .ReplaceWith(m => m.Imdb);
このページのNode.js の例では、Atlasサンプルデータセット の sample_mflixデータベースを使用します。無料のMongoDB Atlas cluster を作成し、サンプルデータセットをロードする方法については、 MongoDB Node.jsドライバーのドキュメントの開始を参照してください。
MongoDB Node.jsドライバーを使用して $replaceWith ステージを集計パイプラインに追加するには、パイプラインオブジェクトで $replaceWith 演算子を使用します。
次の例では、各入力 movieドキュメントをimdbフィールドに保存されているドキュメントに置き換えるパイプラインステージを作成します。次に、この例では集計パイプラインを実行します。
const pipeline = [{ $replaceWith: '$imdb' }]; const cursor = collection.aggregate(pipeline); return cursor;
詳細
関連するパイプラインステージの詳細については、$replaceRootガイドを参照してください。