mongodb - Rename field of complex type that is located in array -
i'm doing refactoring on production database , need create renamings. version of mongodb 1.8.0. utilize c# driver refactoring of database. have faced problem when seek rename field of complex type located in array.
for illustration have such document:
foobarcollection: { field1: "", field2: [ { nestedfield1: "", nestedfield2: "" }, { nestedfield1: "", nestedfield2: "" }, ... ] }
i need rename nestedfield2
nestedfield3
, example. mongodb documentation says:
$rename
version 1.7.2+ only.
{ $rename : { old_field_name : new_field_name } } renames field name 'old_field_name' 'new_field_name'. does not expand arrays find match 'old_field_name'.
as understand, using update.rename()
wouldn't give result, because documentation says "rename - doesn't expand arrays find match old field name"
what c# code should write rename nestedfield2
nestedfield3
?
i have implemented special type renaming of arbitrary field in mongodb. here 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, in array. separate nest level '$': "foofield1$foofieldnested$foofieldnestednested"</param> /// <param name="newfieldname">specify field name without path it: "newfieldname", 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); // document modified in memory - replace old document 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 maintain 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 '$'. 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 []{'$', ' '}) .split(new [] {'$'}, stringsplitoptions.removeemptyentries); homecoming pathsegments.tolist(); } public ienumerator<string> getenumerator() { homecoming segments.getenumerator(); } ienumerator ienumerable.getenumerator() { homecoming getenumerator(); } public string this[int index] { { homecoming segments[index]; } } } }
to separate nest levels utilize '$' sign - sign forbidden collection names in mongo. usage can this:
mongodbrefactorer mongodbrefactorer = new mongodbrefactorer(mongo.database); mongodbrefactorer.renamefield("schools", "foobartypescustom$foobardefaultname", "foobarname");
this code find in collection schools
foobartypescustom
property. can complex type array. find foobardefaultname
properties (if foobartypescustom
array iterate through it) , rename foobarname
. nesting levels , number of nested arrays no matters.
mongodb mongodb-csharp
No comments:
Post a Comment