在 C# 中将 MongoDB 文档导出到 CSV

Exporting MongoDB Documents to CSV in C#

我想使用 C# 从 MongoDB.Driver 的 IMongoCollection 的项目中导出 CSV table。

我怎样才能有效地做到这一点?我正在考虑通过从集合中检索文档并将它们转换为类似 JSON 的格式或使用 StringBuilder 创建 CSV 文件并使用 PropertyInfo 数组来访问检索到的对象的字段。

有人可以举例说明我如何做到这一点吗?

似乎最明显的方法是以某种方式获取所有 header 数据(见下文),然后遍历 collection,如果你要手写(人们不会t鼓励),字符串构建,批量写入文件(如果你的collection非常大)。

HashSet<string> fields = new HashSet<string>();
BsonDocument query = BsonDocument.Parse(filter);
var result = database.GetCollection<BsonDocument>(collection).Find(new BsonDocument());

// Populate fields with all unique fields, see below for examples how.

var csv = new StringBuilder();
string headerLine = string.Join(",", fields);
csv.AppendLine(headerLine);

foreach (var element in result.ToListAsync().Result)
{
    string line = null;
    foreach (var field in fields)
    {
        BsonValue value;
        if (field.Contains("."))
        {
            value = GetNestedField(element, field);
        }
        else
        {
            value = element.GetElement(field).Value;
        }

        // Example deserialize to string
        switch (value.BsonType)
        {
            case BsonType.ObjectId:
                line = line + value.ToString();
                break;
            case BsonType.String:
                line = line + value.ToString();
                break;
            case BsonType.Int32:
                line = line + value.AsInt32.ToString();
                break;
        }
        line = line + ",";
    }
    csv.AppendLine(line);
}
File.WriteAllText("D:\temp.csv", csv.ToString());

对于您自己的 objects,您必须使用自己的反序列化器。

HOWEVER 如果可以的话,我建议您使用 mongoexport 工具。 您可以简单地 运行 来自您的应用程序的 exe,根据需要输入参数。但请记住,它需要显式字段。

ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = "C:\mongodb\bin\mongoexport.exe";
startInfo.Arguments = "-d testDB -c testCollection --type csv --fields name,address.street,address.zipCode --out .\output.csv";
startInfo.UseShellExecute = false;

Process exportProcess= new Process();
exportProcess.StartInfo = startInfo;

exportProcess.Start();
exportProcess.WaitForExit();

有关 mongoexport 的更多信息,例如分页、附加查询和字段文件: https://docs.mongodb.com/manual/reference/program/mongoexport/

获取唯一字段名称

要查找所有字段名称,您可以通过多种方式进行。使用 BsonDocument 作为通用数据示例。

  1. 递归遍历您的 IMongoCollection 结果。这将必须贯穿整个 collection,因此性能可能不会很好。

示例:

HashSet<string> fields = new HashSet<string>();
var result = database.GetCollection<BsonDocument>(collection).Find(new BsonDocument());
var result = database.GetCollection<BsonDocument>(collection).Find(new BsonDocument());
foreach (var element in result.ToListAsync().Result)
{
    ProcessTree(fields, element, "");
}

private void ProcessTree(HashSet<string> fields, BsonDocument tree, string parentField)
{
    foreach (var field in tree)
    {
        string fieldName = field.Name;
        if (parentField != "")
        {
                fieldName = parentField + "." + fieldName;
        }

        if (field.Value.IsBsonDocument)
        {
            ProcessTree(fields, field.Value.ToBsonDocument(), fieldName);
        }
        else
        {
            fields.Add(fieldName);
        }
    }

}

  1. 对 return 所有字段执行 MapReduce 操作。但是,使用此方法扫描嵌套字段变得更加复杂。参见 this

示例:

string map = @"function() { 
    for (var key in this) { emit(key, null); }
}";
string reduce = @"function(key, stuff) { return null; }";
string finalize = @"function(key, value){
    return key;
}";
MapReduceOptions<BsonDocument, BsonValue> options = new MapReduceOptions<BsonDocument, BsonValue>();
options.Finalize = new BsonJavaScript(finalize);

var results = database.GetCollection<BsonDocument>(collection).MapReduceAsync(
    new BsonJavaScript(map),
    new BsonJavaScript(reduce),
    options).Result.ToListAsync().Result;
foreach (BsonValue result in results.Select(item => item["_id"]))
{
    Debug.WriteLine(result.AsString);
}
  1. 执行聚合操作。您需要根据需要展开多次以获得所有嵌套字段。

示例:

string[] pipeline = new string[3];
pipeline[0] = "{ '$project':{ 'arrayofkeyvalue':{ '$objectToArray':'$$ROOT'}}}";
pipeline[1] = "{ '$unwind':'$arrayofkeyvalue'}";
pipeline[2] = "{ '$group':{'_id':null,'fieldKeys':{'$addToSet':'$arrayofkeyvalue.k'}}}";
var stages = pipeline.Select(s => BsonDocument.Parse(s)).ToList();
var result = await database.GetCollection<BsonDocument>(collection).AggregateAsync<BsonDocument>(stages);
foreach (BsonValue fieldName in result.Single().GetElement("fieldKeys").Value.AsBsonArray)
{
    Debug.WriteLine(fieldName.AsString);
}

这里没有完美的东西,我无法告诉你哪个是最有效的,但希望能有所帮助。