重命名位于数组中的复杂类型的字段

发布于 2024-11-30 09:38:00 字数 757 浏览 0 评论 0原文

我正在对生产数据库进行重构,需要进行一些重命名。 mongodb的版本是1.8.0。我使用 C# 驱动程序来重构数据库。当我尝试重命名位于数组中的复杂类型的字段时遇到问题。

例如,我有这样的文档:

FoobarCollection:

{
  Field1: "",
  Field2: [
    { NestedField1: "", NestedField2: "" },
    { NestedField1: "", NestedField2: "" },
    ... 
  ]
}

例如,我需要将 NestedField2 重命名为 NestedField3 。 MongoDB 文档说:

$重命名

仅限 1.7.2+ 版本。

{ $rename : { 旧字段名称 : 新字段名称 } } 将名称为“old_field_name”的字段重命名为“new_field_name”。 不会扩展数组来查找“old_field_name”的匹配项

据我了解,简单地使用 Update.Rename() 不会给出结果,因为正如文档所说“重命名 - 不会扩展数组以查找旧字段名称的匹配项”

我应该使用什么 C# 代码写入将 NestedField2 重命名为 NestedField3

I'm doing refactoring on production database and need to make some renamings. Version of mongodb is 1.8.0. I use C# driver to do refactoring of database. Have faced with problem when I try to rename field of complex type that is located in array.

For example I have such document:

FoobarCollection:

{
  Field1: "",
  Field2: [
    { NestedField1: "", NestedField2: "" },
    { NestedField1: "", NestedField2: "" },
    ... 
  ]
}

I Need to rename NestedField2 into NestedField3, for example.
MongoDB documentation says:

$rename

Version 1.7.2+ only.

{ $rename : { old_field_name : new_field_name } }
Renames the field with name 'old_field_name' to 'new_field_name'. Does not expand arrays to find a match for 'old_field_name'.

As I understand, simply using Update.Rename() wouldn't give result, because as documentation says "rename - doesn't expand arrays to find a match for old field name"

What C# code I should write to rename NestedField2 into NestedField3?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你如我软肋 2024-12-07 09:38:00

我已经实现了特殊类型来重命名 MongoDB 中的任意字段。就是这样:

using System.Linq;
using MongoDB.Bson;
using MongoDB.Driver;

namespace DatabaseManagementTools
{
    public class MongoDbRefactorer
    {
        protected MongoDatabase MongoDatabase { get; set; }

        public MongoDbRefactorer(MongoDatabase mongoDatabase)
        {
            MongoDatabase = mongoDatabase;
        }

        /// <summary>
        /// Renames field
        /// </summary>
        /// <param name="collectionName"></param>
        /// <param name="oldFieldNamePath">Supports nested types, even in array. Separate nest level with '

用于保留路径段的辅助类型:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace DatabaseManagementTools
{
    public class PathSegments : IEnumerable<string>
    {
        private List<string> Segments { get; set; }

        /// <summary>
        /// Split segment levels with '

为了分隔嵌套级别,我使用“$”符号 - 这是 mongo 中唯一禁止用于集合名称的符号。
用法可以是这样的:

MongoDbRefactorer mongoDbRefactorer = new MongoDbRefactorer(Mongo.Database);
mongoDbRefactorer.RenameField("schools", "FoobarTypesCustom$FoobarDefaultName", "FoobarName");

此代码将在集合 schools FoobarTypesCustom 属性中找到。它可以是复杂类型,也可以是数组。然后将找到所有 FoobarDefaultName 属性(如果 FoobarTypesCustom 是数组,那么它将迭代它)并将其重命名为 FoobarName。嵌套级别和嵌套数组的数量并不重要。

: "FooField1$FooFieldNested$FooFieldNestedNested"</param> /// <param name="newFieldName">Specify only field name without path to it: "NewFieldName", but not "FooField1$NewFieldName"</param> public void RenameField(string collectionName, string oldFieldNamePath, string newFieldName) { MongoCollection<BsonDocument> mongoCollection = MongoDatabase.GetCollection(collectionName); MongoCursor<BsonDocument> collectionCursor = mongoCollection.FindAll(); PathSegments pathSegments = new PathSegments(oldFieldNamePath); // Rename field in each document of collection foreach (BsonDocument document in collectionCursor) { int currentSegmentIndex = 0; RenameField(document, pathSegments, currentSegmentIndex, newFieldName); // Now document is modified in memory - replace old document with new in mongo: mongoCollection.Save(document); } } private void RenameField(BsonValue bsonValue, PathSegments pathSegments, int currentSegmentIndex, string newFieldName) { string currentSegmentName = pathSegments[currentSegmentIndex]; if (bsonValue.IsBsonArray) { var array = bsonValue.AsBsonArray; foreach (var arrayElement in array) { RenameField(arrayElement.AsBsonDocument, pathSegments, currentSegmentIndex, newFieldName); } return; } bool isLastNameSegment = pathSegments.Count() == currentSegmentIndex + 1; if (isLastNameSegment) { RenameDirect(bsonValue, currentSegmentName, newFieldName); return; } var innerDocument = bsonValue.AsBsonDocument[currentSegmentName]; RenameField(innerDocument, pathSegments, currentSegmentIndex + 1, newFieldName); } private void RenameDirect(BsonValue document, string from, string to) { BsonElement bsonValue; bool elementFound = document.AsBsonDocument.TryGetElement(from, out bsonValue); if (elementFound) { document.AsBsonDocument.Add(to, bsonValue.Value); document.AsBsonDocument.Remove(from); } else { // todo: log missing elements } } } }

用于保留路径段的辅助类型:


为了分隔嵌套级别,我使用“$”符号 - 这是 mongo 中唯一禁止用于集合名称的符号。
用法可以是这样的:


此代码将在集合 schools FoobarTypesCustom 属性中找到。它可以是复杂类型,也可以是数组。然后将找到所有 FoobarDefaultName 属性(如果 FoobarTypesCustom 是数组,那么它将迭代它)并将其重命名为 FoobarName。嵌套级别和嵌套数组的数量并不重要。

. For example: "School$CustomCodes" /// </summary> /// <param name="pathToParse"></param> public PathSegments(string pathToParse) { Segments = ParseSegments(pathToParse); } private static List<string> ParseSegments(string oldFieldNamePath) { string[] pathSegments = oldFieldNamePath.Trim(new []{'

为了分隔嵌套级别,我使用“$”符号 - 这是 mongo 中唯一禁止用于集合名称的符号。
用法可以是这样的:


此代码将在集合 schools FoobarTypesCustom 属性中找到。它可以是复杂类型,也可以是数组。然后将找到所有 FoobarDefaultName 属性(如果 FoobarTypesCustom 是数组,那么它将迭代它)并将其重命名为 FoobarName。嵌套级别和嵌套数组的数量并不重要。

: "FooField1$FooFieldNested$FooFieldNestedNested"</param> /// <param name="newFieldName">Specify only field name without path to it: "NewFieldName", but not "FooField1$NewFieldName"</param> public void RenameField(string collectionName, string oldFieldNamePath, string newFieldName) { MongoCollection<BsonDocument> mongoCollection = MongoDatabase.GetCollection(collectionName); MongoCursor<BsonDocument> collectionCursor = mongoCollection.FindAll(); PathSegments pathSegments = new PathSegments(oldFieldNamePath); // Rename field in each document of collection foreach (BsonDocument document in collectionCursor) { int currentSegmentIndex = 0; RenameField(document, pathSegments, currentSegmentIndex, newFieldName); // Now document is modified in memory - replace old document with new in mongo: mongoCollection.Save(document); } } private void RenameField(BsonValue bsonValue, PathSegments pathSegments, int currentSegmentIndex, string newFieldName) { string currentSegmentName = pathSegments[currentSegmentIndex]; if (bsonValue.IsBsonArray) { var array = bsonValue.AsBsonArray; foreach (var arrayElement in array) { RenameField(arrayElement.AsBsonDocument, pathSegments, currentSegmentIndex, newFieldName); } return; } bool isLastNameSegment = pathSegments.Count() == currentSegmentIndex + 1; if (isLastNameSegment) { RenameDirect(bsonValue, currentSegmentName, newFieldName); return; } var innerDocument = bsonValue.AsBsonDocument[currentSegmentName]; RenameField(innerDocument, pathSegments, currentSegmentIndex + 1, newFieldName); } private void RenameDirect(BsonValue document, string from, string to) { BsonElement bsonValue; bool elementFound = document.AsBsonDocument.TryGetElement(from, out bsonValue); if (elementFound) { document.AsBsonDocument.Add(to, bsonValue.Value); document.AsBsonDocument.Remove(from); } else { // todo: log missing elements } } } }

用于保留路径段的辅助类型:

为了分隔嵌套级别,我使用“$”符号 - 这是 mongo 中唯一禁止用于集合名称的符号。
用法可以是这样的:

此代码将在集合 schools FoobarTypesCustom 属性中找到。它可以是复杂类型,也可以是数组。然后将找到所有 FoobarDefaultName 属性(如果 FoobarTypesCustom 是数组,那么它将迭代它)并将其重命名为 FoobarName。嵌套级别和嵌套数组的数量并不重要。

, ' '}) .Split(new [] {'

为了分隔嵌套级别,我使用“$”符号 - 这是 mongo 中唯一禁止用于集合名称的符号。
用法可以是这样的:

此代码将在集合 schools FoobarTypesCustom 属性中找到。它可以是复杂类型,也可以是数组。然后将找到所有 FoobarDefaultName 属性(如果 FoobarTypesCustom 是数组,那么它将迭代它)并将其重命名为 FoobarName。嵌套级别和嵌套数组的数量并不重要。

: "FooField1$FooFieldNested$FooFieldNestedNested"</param> /// <param name="newFieldName">Specify only field name without path to it: "NewFieldName", but not "FooField1$NewFieldName"</param> public void RenameField(string collectionName, string oldFieldNamePath, string newFieldName) { MongoCollection<BsonDocument> mongoCollection = MongoDatabase.GetCollection(collectionName); MongoCursor<BsonDocument> collectionCursor = mongoCollection.FindAll(); PathSegments pathSegments = new PathSegments(oldFieldNamePath); // Rename field in each document of collection foreach (BsonDocument document in collectionCursor) { int currentSegmentIndex = 0; RenameField(document, pathSegments, currentSegmentIndex, newFieldName); // Now document is modified in memory - replace old document with new in mongo: mongoCollection.Save(document); } } private void RenameField(BsonValue bsonValue, PathSegments pathSegments, int currentSegmentIndex, string newFieldName) { string currentSegmentName = pathSegments[currentSegmentIndex]; if (bsonValue.IsBsonArray) { var array = bsonValue.AsBsonArray; foreach (var arrayElement in array) { RenameField(arrayElement.AsBsonDocument, pathSegments, currentSegmentIndex, newFieldName); } return; } bool isLastNameSegment = pathSegments.Count() == currentSegmentIndex + 1; if (isLastNameSegment) { RenameDirect(bsonValue, currentSegmentName, newFieldName); return; } var innerDocument = bsonValue.AsBsonDocument[currentSegmentName]; RenameField(innerDocument, pathSegments, currentSegmentIndex + 1, newFieldName); } private void RenameDirect(BsonValue document, string from, string to) { BsonElement bsonValue; bool elementFound = document.AsBsonDocument.TryGetElement(from, out bsonValue); if (elementFound) { document.AsBsonDocument.Add(to, bsonValue.Value); document.AsBsonDocument.Remove(from); } else { // todo: log missing elements } } } }

用于保留路径段的辅助类型:

为了分隔嵌套级别,我使用“$”符号 - 这是 mongo 中唯一禁止用于集合名称的符号。
用法可以是这样的:

此代码将在集合 schools FoobarTypesCustom 属性中找到。它可以是复杂类型,也可以是数组。然后将找到所有 FoobarDefaultName 属性(如果 FoobarTypesCustom 是数组,那么它将迭代它)并将其重命名为 FoobarName。嵌套级别和嵌套数组的数量并不重要。

}, StringSplitOptions.RemoveEmptyEntries); return pathSegments.ToList(); } public IEnumerator<string> GetEnumerator() { return Segments.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public string this[int index] { get { return Segments[index]; } } } }

为了分隔嵌套级别,我使用“$”符号 - 这是 mongo 中唯一禁止用于集合名称的符号。
用法可以是这样的:

此代码将在集合 schools FoobarTypesCustom 属性中找到。它可以是复杂类型,也可以是数组。然后将找到所有 FoobarDefaultName 属性(如果 FoobarTypesCustom 是数组,那么它将迭代它)并将其重命名为 FoobarName。嵌套级别和嵌套数组的数量并不重要。

: "FooField1$FooFieldNested$FooFieldNestedNested"</param> /// <param name="newFieldName">Specify only field name without path to it: "NewFieldName", but not "FooField1$NewFieldName"</param> public void RenameField(string collectionName, string oldFieldNamePath, string newFieldName) { MongoCollection<BsonDocument> mongoCollection = MongoDatabase.GetCollection(collectionName); MongoCursor<BsonDocument> collectionCursor = mongoCollection.FindAll(); PathSegments pathSegments = new PathSegments(oldFieldNamePath); // Rename field in each document of collection foreach (BsonDocument document in collectionCursor) { int currentSegmentIndex = 0; RenameField(document, pathSegments, currentSegmentIndex, newFieldName); // Now document is modified in memory - replace old document with new in mongo: mongoCollection.Save(document); } } private void RenameField(BsonValue bsonValue, PathSegments pathSegments, int currentSegmentIndex, string newFieldName) { string currentSegmentName = pathSegments[currentSegmentIndex]; if (bsonValue.IsBsonArray) { var array = bsonValue.AsBsonArray; foreach (var arrayElement in array) { RenameField(arrayElement.AsBsonDocument, pathSegments, currentSegmentIndex, newFieldName); } return; } bool isLastNameSegment = pathSegments.Count() == currentSegmentIndex + 1; if (isLastNameSegment) { RenameDirect(bsonValue, currentSegmentName, newFieldName); return; } var innerDocument = bsonValue.AsBsonDocument[currentSegmentName]; RenameField(innerDocument, pathSegments, currentSegmentIndex + 1, newFieldName); } private void RenameDirect(BsonValue document, string from, string to) { BsonElement bsonValue; bool elementFound = document.AsBsonDocument.TryGetElement(from, out bsonValue); if (elementFound) { document.AsBsonDocument.Add(to, bsonValue.Value); document.AsBsonDocument.Remove(from); } else { // todo: log missing elements } } } }

用于保留路径段的辅助类型:

为了分隔嵌套级别,我使用“$”符号 - 这是 mongo 中唯一禁止用于集合名称的符号。
用法可以是这样的:

此代码将在集合 schools FoobarTypesCustom 属性中找到。它可以是复杂类型,也可以是数组。然后将找到所有 FoobarDefaultName 属性(如果 FoobarTypesCustom 是数组,那么它将迭代它)并将其重命名为 FoobarName。嵌套级别和嵌套数组的数量并不重要。

I have implemented special type to do renaming of arbitrary field in MongoDB. Here is it:

using System.Linq;
using MongoDB.Bson;
using MongoDB.Driver;

namespace DatabaseManagementTools
{
    public class MongoDbRefactorer
    {
        protected MongoDatabase MongoDatabase { get; set; }

        public MongoDbRefactorer(MongoDatabase mongoDatabase)
        {
            MongoDatabase = mongoDatabase;
        }

        /// <summary>
        /// Renames field
        /// </summary>
        /// <param name="collectionName"></param>
        /// <param name="oldFieldNamePath">Supports nested types, even in array. Separate nest level with '

And helper type to keep path segments:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace DatabaseManagementTools
{
    public class PathSegments : IEnumerable<string>
    {
        private List<string> Segments { get; set; }

        /// <summary>
        /// Split segment levels with '

To separate nest levels I use '$' sign - the only sign that is forbidden for collection names in mongo.
Usage can be something like this:

MongoDbRefactorer mongoDbRefactorer = new MongoDbRefactorer(Mongo.Database);
mongoDbRefactorer.RenameField("schools", "FoobarTypesCustom$FoobarDefaultName", "FoobarName");

This code will find in collection schools FoobarTypesCustom property. It can be as complex type so array. Then will find all FoobarDefaultName properties (if FoobarTypesCustom is array then it will iterate through it) and rename it to FoobarName. Nesting levels and number of nested arrays no matters.

: "FooField1$FooFieldNested$FooFieldNestedNested"</param> /// <param name="newFieldName">Specify only field name without path to it: "NewFieldName", but not "FooField1$NewFieldName"</param> public void RenameField(string collectionName, string oldFieldNamePath, string newFieldName) { MongoCollection<BsonDocument> mongoCollection = MongoDatabase.GetCollection(collectionName); MongoCursor<BsonDocument> collectionCursor = mongoCollection.FindAll(); PathSegments pathSegments = new PathSegments(oldFieldNamePath); // Rename field in each document of collection foreach (BsonDocument document in collectionCursor) { int currentSegmentIndex = 0; RenameField(document, pathSegments, currentSegmentIndex, newFieldName); // Now document is modified in memory - replace old document with new in mongo: mongoCollection.Save(document); } } private void RenameField(BsonValue bsonValue, PathSegments pathSegments, int currentSegmentIndex, string newFieldName) { string currentSegmentName = pathSegments[currentSegmentIndex]; if (bsonValue.IsBsonArray) { var array = bsonValue.AsBsonArray; foreach (var arrayElement in array) { RenameField(arrayElement.AsBsonDocument, pathSegments, currentSegmentIndex, newFieldName); } return; } bool isLastNameSegment = pathSegments.Count() == currentSegmentIndex + 1; if (isLastNameSegment) { RenameDirect(bsonValue, currentSegmentName, newFieldName); return; } var innerDocument = bsonValue.AsBsonDocument[currentSegmentName]; RenameField(innerDocument, pathSegments, currentSegmentIndex + 1, newFieldName); } private void RenameDirect(BsonValue document, string from, string to) { BsonElement bsonValue; bool elementFound = document.AsBsonDocument.TryGetElement(from, out bsonValue); if (elementFound) { document.AsBsonDocument.Add(to, bsonValue.Value); document.AsBsonDocument.Remove(from); } else { // todo: log missing elements } } } }

And helper type to keep path segments:


To separate nest levels I use '$' sign - the only sign that is forbidden for collection names in mongo.
Usage can be something like this:


This code will find in collection schools FoobarTypesCustom property. It can be as complex type so array. Then will find all FoobarDefaultName properties (if FoobarTypesCustom is array then it will iterate through it) and rename it to FoobarName. Nesting levels and number of nested arrays no matters.

. For example: "School$CustomCodes" /// </summary> /// <param name="pathToParse"></param> public PathSegments(string pathToParse) { Segments = ParseSegments(pathToParse); } private static List<string> ParseSegments(string oldFieldNamePath) { string[] pathSegments = oldFieldNamePath.Trim(new []{'

To separate nest levels I use '$' sign - the only sign that is forbidden for collection names in mongo.
Usage can be something like this:


This code will find in collection schools FoobarTypesCustom property. It can be as complex type so array. Then will find all FoobarDefaultName properties (if FoobarTypesCustom is array then it will iterate through it) and rename it to FoobarName. Nesting levels and number of nested arrays no matters.

: "FooField1$FooFieldNested$FooFieldNestedNested"</param> /// <param name="newFieldName">Specify only field name without path to it: "NewFieldName", but not "FooField1$NewFieldName"</param> public void RenameField(string collectionName, string oldFieldNamePath, string newFieldName) { MongoCollection<BsonDocument> mongoCollection = MongoDatabase.GetCollection(collectionName); MongoCursor<BsonDocument> collectionCursor = mongoCollection.FindAll(); PathSegments pathSegments = new PathSegments(oldFieldNamePath); // Rename field in each document of collection foreach (BsonDocument document in collectionCursor) { int currentSegmentIndex = 0; RenameField(document, pathSegments, currentSegmentIndex, newFieldName); // Now document is modified in memory - replace old document with new in mongo: mongoCollection.Save(document); } } private void RenameField(BsonValue bsonValue, PathSegments pathSegments, int currentSegmentIndex, string newFieldName) { string currentSegmentName = pathSegments[currentSegmentIndex]; if (bsonValue.IsBsonArray) { var array = bsonValue.AsBsonArray; foreach (var arrayElement in array) { RenameField(arrayElement.AsBsonDocument, pathSegments, currentSegmentIndex, newFieldName); } return; } bool isLastNameSegment = pathSegments.Count() == currentSegmentIndex + 1; if (isLastNameSegment) { RenameDirect(bsonValue, currentSegmentName, newFieldName); return; } var innerDocument = bsonValue.AsBsonDocument[currentSegmentName]; RenameField(innerDocument, pathSegments, currentSegmentIndex + 1, newFieldName); } private void RenameDirect(BsonValue document, string from, string to) { BsonElement bsonValue; bool elementFound = document.AsBsonDocument.TryGetElement(from, out bsonValue); if (elementFound) { document.AsBsonDocument.Add(to, bsonValue.Value); document.AsBsonDocument.Remove(from); } else { // todo: log missing elements } } } }

And helper type to keep path segments:

To separate nest levels I use '$' sign - the only sign that is forbidden for collection names in mongo.
Usage can be something like this:

This code will find in collection schools FoobarTypesCustom property. It can be as complex type so array. Then will find all FoobarDefaultName properties (if FoobarTypesCustom is array then it will iterate through it) and rename it to FoobarName. Nesting levels and number of nested arrays no matters.

, ' '}) .Split(new [] {'

To separate nest levels I use '$' sign - the only sign that is forbidden for collection names in mongo.
Usage can be something like this:

This code will find in collection schools FoobarTypesCustom property. It can be as complex type so array. Then will find all FoobarDefaultName properties (if FoobarTypesCustom is array then it will iterate through it) and rename it to FoobarName. Nesting levels and number of nested arrays no matters.

: "FooField1$FooFieldNested$FooFieldNestedNested"</param> /// <param name="newFieldName">Specify only field name without path to it: "NewFieldName", but not "FooField1$NewFieldName"</param> public void RenameField(string collectionName, string oldFieldNamePath, string newFieldName) { MongoCollection<BsonDocument> mongoCollection = MongoDatabase.GetCollection(collectionName); MongoCursor<BsonDocument> collectionCursor = mongoCollection.FindAll(); PathSegments pathSegments = new PathSegments(oldFieldNamePath); // Rename field in each document of collection foreach (BsonDocument document in collectionCursor) { int currentSegmentIndex = 0; RenameField(document, pathSegments, currentSegmentIndex, newFieldName); // Now document is modified in memory - replace old document with new in mongo: mongoCollection.Save(document); } } private void RenameField(BsonValue bsonValue, PathSegments pathSegments, int currentSegmentIndex, string newFieldName) { string currentSegmentName = pathSegments[currentSegmentIndex]; if (bsonValue.IsBsonArray) { var array = bsonValue.AsBsonArray; foreach (var arrayElement in array) { RenameField(arrayElement.AsBsonDocument, pathSegments, currentSegmentIndex, newFieldName); } return; } bool isLastNameSegment = pathSegments.Count() == currentSegmentIndex + 1; if (isLastNameSegment) { RenameDirect(bsonValue, currentSegmentName, newFieldName); return; } var innerDocument = bsonValue.AsBsonDocument[currentSegmentName]; RenameField(innerDocument, pathSegments, currentSegmentIndex + 1, newFieldName); } private void RenameDirect(BsonValue document, string from, string to) { BsonElement bsonValue; bool elementFound = document.AsBsonDocument.TryGetElement(from, out bsonValue); if (elementFound) { document.AsBsonDocument.Add(to, bsonValue.Value); document.AsBsonDocument.Remove(from); } else { // todo: log missing elements } } } }

And helper type to keep path segments:

To separate nest levels I use '$' sign - the only sign that is forbidden for collection names in mongo.
Usage can be something like this:

This code will find in collection schools FoobarTypesCustom property. It can be as complex type so array. Then will find all FoobarDefaultName properties (if FoobarTypesCustom is array then it will iterate through it) and rename it to FoobarName. Nesting levels and number of nested arrays no matters.

}, StringSplitOptions.RemoveEmptyEntries); return pathSegments.ToList(); } public IEnumerator<string> GetEnumerator() { return Segments.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public string this[int index] { get { return Segments[index]; } } } }

To separate nest levels I use '$' sign - the only sign that is forbidden for collection names in mongo.
Usage can be something like this:

This code will find in collection schools FoobarTypesCustom property. It can be as complex type so array. Then will find all FoobarDefaultName properties (if FoobarTypesCustom is array then it will iterate through it) and rename it to FoobarName. Nesting levels and number of nested arrays no matters.

: "FooField1$FooFieldNested$FooFieldNestedNested"</param> /// <param name="newFieldName">Specify only field name without path to it: "NewFieldName", but not "FooField1$NewFieldName"</param> public void RenameField(string collectionName, string oldFieldNamePath, string newFieldName) { MongoCollection<BsonDocument> mongoCollection = MongoDatabase.GetCollection(collectionName); MongoCursor<BsonDocument> collectionCursor = mongoCollection.FindAll(); PathSegments pathSegments = new PathSegments(oldFieldNamePath); // Rename field in each document of collection foreach (BsonDocument document in collectionCursor) { int currentSegmentIndex = 0; RenameField(document, pathSegments, currentSegmentIndex, newFieldName); // Now document is modified in memory - replace old document with new in mongo: mongoCollection.Save(document); } } private void RenameField(BsonValue bsonValue, PathSegments pathSegments, int currentSegmentIndex, string newFieldName) { string currentSegmentName = pathSegments[currentSegmentIndex]; if (bsonValue.IsBsonArray) { var array = bsonValue.AsBsonArray; foreach (var arrayElement in array) { RenameField(arrayElement.AsBsonDocument, pathSegments, currentSegmentIndex, newFieldName); } return; } bool isLastNameSegment = pathSegments.Count() == currentSegmentIndex + 1; if (isLastNameSegment) { RenameDirect(bsonValue, currentSegmentName, newFieldName); return; } var innerDocument = bsonValue.AsBsonDocument[currentSegmentName]; RenameField(innerDocument, pathSegments, currentSegmentIndex + 1, newFieldName); } private void RenameDirect(BsonValue document, string from, string to) { BsonElement bsonValue; bool elementFound = document.AsBsonDocument.TryGetElement(from, out bsonValue); if (elementFound) { document.AsBsonDocument.Add(to, bsonValue.Value); document.AsBsonDocument.Remove(from); } else { // todo: log missing elements } } } }

And helper type to keep path segments:

To separate nest levels I use '$' sign - the only sign that is forbidden for collection names in mongo.
Usage can be something like this:

This code will find in collection schools FoobarTypesCustom property. It can be as complex type so array. Then will find all FoobarDefaultName properties (if FoobarTypesCustom is array then it will iterate through it) and rename it to FoobarName. Nesting levels and number of nested arrays no matters.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文