如何使用 AggregateToCollection() 将 IMongoQueryable 的结果存储在集合中
How to use AggregateToCollection() to store the results of an IMongoQueryable in a collection
除非我遗漏了什么,否则 C# MongoDb 驱动程序的文档中似乎存在很大差距。
我正在尝试获取 IMongoQueryable
(这是各种 LINQ Where、Select 等操作的结果)并将结果存储在数据库端的集合中。当然,我可以在客户端遍历它并以这种方式持久化它,但即使是批量处理也效率不高,而且在 shell 中使用 $merge
或 [=13= 是一个非常简单的操作].
在一个集合中,有方法 AggregateToCollection<TResult>()
这正是我想要的,但它需要一个 PiplineDefinition<TDocument, TResult>
参数,我不知道如何从 [=11] 实际生成=].
我一直在尝试在 IMongoQueryable
上使用 GetExecutionModel()
来获得 BsonDocument
或 Json 字符串,但我仍然没有提示如何将其变成我需要的 PipelineDefinition
!
我原以为我会找到 IMongoQueryable
上的扩展方法,它允许我将其发送并合并到一个集合中。
到目前为止,为了能够将 IMongoQueryable
发送到集合,我有一些类似的东西:
var executionModelDocument = queryable.GetExecutionModel().ToBsonDocument();
// somehow turn the document into pipeline stages and a pipeline??
await _database.GetCollection<TDocument>().AggregateToCollectionAsync<TResult>(pipeline);
我该如何真正做到这一点?
好吧,这最终比预期的要容易,但仍然令人沮丧。
首先,事实证明您可以通过调用 ToString()
从 IMongoQueryable
作为 JSON 获取管道。虽然我说 JSON,但不完全是 - 输出包含管道的完整 JSON 作为阶段数组,但前面有一个标签并在括号内包含 JSON。我这里抄了个捷径,直接拿了个脏子串:
var queryableJson = queryable.ToString();
var trimmedDocument = queryableJson.Substring(10, queryableJson.Length - 11); // TODO: more reliably get the true json rather than blindly removing what should be "aggregate(" and ")"
接下来,我将 JSON 重新序列化为 BsonDocument
的数组,并从中生成一个 PipelineDefinition
(BsonDocument[]
可以隐式转换为一个 PipelineDefinition
):
PipelineDefinition<TDocument, TResult> pipelineQueryable = BsonSerializer.Deserialize<BsonDocument[]>(trimmedDocument);
请注意,虽然 http://mongodb.github.io/mongo-csharp-driver/2.4/reference/driver/definitions/#pipelines 处的文档说我可以隐式地为管道投射单个 BsonDocument
而不是阶段数组,但除非在另一个命名空间中有重载,否则这是不正确的我没找到。
到目前为止,我们已经为 IMongoQueryable 定义了一个管道,我们可以简单地向其添加阶段以获得我们想要的结果(在本例中,将管道的结果合并到另一个集合中)。您可以指定 MergeStageOptions<TResult>
对象的属性来控制行为,但默认值对我来说很好用:
var stageMerge = PipelineStageDefinitionBuilder.Merge<TResult, TResult>(_database.GetCollection<TResult>(), new MergeStageOptions<TResult>());
var mergePipeline = pipelineQueryable.AppendStage(stageMerge);
使用我们新增强的管道,我们可以将其应用于源集合以将输出合并到目标集合中:
_database.GetCollection<TDocument>().AggregateToCollection(mergePipeline);
为简单起见,我在这里演示的不是异步的,但是我在实际代码中利用了驱动程序中的可等待方法,因为同步方法只是包装了可等待的版本。
真的就这些了!当我有更多时间时,我将返回并尝试跳过序列化-反序列化步骤,因为它明显很慢并且没有必要。为了流畅起见,我也打算把它变成一个扩展方法。
除非我遗漏了什么,否则 C# MongoDb 驱动程序的文档中似乎存在很大差距。
我正在尝试获取 IMongoQueryable
(这是各种 LINQ Where、Select 等操作的结果)并将结果存储在数据库端的集合中。当然,我可以在客户端遍历它并以这种方式持久化它,但即使是批量处理也效率不高,而且在 shell 中使用 $merge
或 [=13= 是一个非常简单的操作].
在一个集合中,有方法 AggregateToCollection<TResult>()
这正是我想要的,但它需要一个 PiplineDefinition<TDocument, TResult>
参数,我不知道如何从 [=11] 实际生成=].
我一直在尝试在 IMongoQueryable
上使用 GetExecutionModel()
来获得 BsonDocument
或 Json 字符串,但我仍然没有提示如何将其变成我需要的 PipelineDefinition
!
我原以为我会找到 IMongoQueryable
上的扩展方法,它允许我将其发送并合并到一个集合中。
到目前为止,为了能够将 IMongoQueryable
发送到集合,我有一些类似的东西:
var executionModelDocument = queryable.GetExecutionModel().ToBsonDocument();
// somehow turn the document into pipeline stages and a pipeline??
await _database.GetCollection<TDocument>().AggregateToCollectionAsync<TResult>(pipeline);
我该如何真正做到这一点?
好吧,这最终比预期的要容易,但仍然令人沮丧。
首先,事实证明您可以通过调用 ToString()
从 IMongoQueryable
作为 JSON 获取管道。虽然我说 JSON,但不完全是 - 输出包含管道的完整 JSON 作为阶段数组,但前面有一个标签并在括号内包含 JSON。我这里抄了个捷径,直接拿了个脏子串:
var queryableJson = queryable.ToString();
var trimmedDocument = queryableJson.Substring(10, queryableJson.Length - 11); // TODO: more reliably get the true json rather than blindly removing what should be "aggregate(" and ")"
接下来,我将 JSON 重新序列化为 BsonDocument
的数组,并从中生成一个 PipelineDefinition
(BsonDocument[]
可以隐式转换为一个 PipelineDefinition
):
PipelineDefinition<TDocument, TResult> pipelineQueryable = BsonSerializer.Deserialize<BsonDocument[]>(trimmedDocument);
请注意,虽然 http://mongodb.github.io/mongo-csharp-driver/2.4/reference/driver/definitions/#pipelines 处的文档说我可以隐式地为管道投射单个 BsonDocument
而不是阶段数组,但除非在另一个命名空间中有重载,否则这是不正确的我没找到。
到目前为止,我们已经为 IMongoQueryable 定义了一个管道,我们可以简单地向其添加阶段以获得我们想要的结果(在本例中,将管道的结果合并到另一个集合中)。您可以指定 MergeStageOptions<TResult>
对象的属性来控制行为,但默认值对我来说很好用:
var stageMerge = PipelineStageDefinitionBuilder.Merge<TResult, TResult>(_database.GetCollection<TResult>(), new MergeStageOptions<TResult>());
var mergePipeline = pipelineQueryable.AppendStage(stageMerge);
使用我们新增强的管道,我们可以将其应用于源集合以将输出合并到目标集合中:
_database.GetCollection<TDocument>().AggregateToCollection(mergePipeline);
为简单起见,我在这里演示的不是异步的,但是我在实际代码中利用了驱动程序中的可等待方法,因为同步方法只是包装了可等待的版本。
真的就这些了!当我有更多时间时,我将返回并尝试跳过序列化-反序列化步骤,因为它明显很慢并且没有必要。为了流畅起见,我也打算把它变成一个扩展方法。