I am running the code below and receiving the subsequent error:
Code:
using MongoDB.Bson;
using MongoDB.Driver;
using System.Collections.Generic;
namespace MongoBulkWriteSerializationFailure
{
class Person
{
public string Firstname;
public string Lastname;
}
class DummyClient
{
private IMongoCollection<BsonDocument> _collection;
public DummyClient()
{
_collection = (new MongoClient("mongodb://root:password@localhost:27017/")).GetDatabase("my_db").GetCollection<BsonDocument>("persons");
}
public void Upsert(Person person)
{
List<WriteModel<BsonDocument>> list_of_operations = new List<WriteModel<BsonDocument>>();
ReplaceOneModel<BsonDocument> write_model = new ReplaceOneModel<BsonDocument>($"{{ 'firstname': '{person.Firstname}', 'lastname': '{person.Lastname}'}}", person.ToBsonDocument());
write_model.IsUpsert = true;
list_of_operations.Add(write_model);
BulkWriteResult<BsonDocument> outcome = _collection.BulkWrite(list_of_operations, new BulkWriteOptions { IsOrdered = false });
System.Console.WriteLine($"Processed {outcome.ProcessedRequests.Count} item(s)");
}
}
class Program
{
static void Main(string[] args)
{
DummyClient client = new DummyClient();
// Successful Control test:
((new MongoClient("mongodb://root:password@localhost:27017/")).GetDatabase("my_db").GetCollection<BsonDocument>("persons")).InsertOne((new Person { Firstname = "John\\1", Lastname = "Smith" }).ToBsonDocument());
// Successful operation:
client.Upsert(new Person { Firstname = "Mike", Lastname = "Smith" });
// Failing operation:
client.Upsert(new Person { Firstname = "Nick\\1", Lastname = "Smith" });
}
}
}
Error:
System.FormatException
HResult=0x80131537
Message=Invalid escape sequence in JSON string '\1'.
Source=MongoDB.Bson
StackTrace:
at MongoDB.Bson.IO.JsonScanner.GetStringToken(JsonBuffer buffer, Char quoteCharacter)
at MongoDB.Bson.IO.JsonScanner.GetNextToken(JsonBuffer buffer)
at MongoDB.Bson.IO.JsonReader.PopToken()
at MongoDB.Bson.IO.JsonReader.ReadBsonType()
at MongoDB.Bson.Serialization.Serializers.BsonDocumentSerializer.DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args)
at MongoDB.Bson.Serialization.Serializers.BsonValueSerializerBase`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context)
at MongoDB.Bson.BsonDocument.Parse(String json)
at MongoDB.Driver.JsonFilterDefinition`1.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry)
at MongoDB.Driver.MongoCollectionImpl`1.ConvertWriteModelToWriteRequest(WriteModel`1 model, Int32 index)
at System.Linq.Enumerable.<SelectIterator>d__5`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation..ctor(CollectionNamespace collectionNamespace, IEnumerable`1 requests, MessageEncoderSettings messageEncoderSettings)
at MongoDB.Driver.MongoCollectionImpl`1.CreateBulkWriteOperation(IEnumerable`1 requests, BulkWriteOptions options)
at MongoDB.Driver.MongoCollectionImpl`1.BulkWrite(IClientSessionHandle session, IEnumerable`1 requests, BulkWriteOptions options, CancellationToken cancellationToken)
at MongoDB.Driver.MongoCollectionImpl`1.<>c__DisplayClass23_0.<BulkWrite>b__0(IClientSessionHandle session)
at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSession[TResult](Func`2 func, CancellationToken cancellationToken)
at MongoDB.Driver.MongoCollectionImpl`1.BulkWrite(IEnumerable`1 requests, BulkWriteOptions options, CancellationToken cancellationToken)
at MongoBulkWriteSerializationFailure.DummyClient.Upsert(Person person) in C:\code\MongoBulkWriteSerializationFailure\Program.cs:line 28
at MongoBulkWriteSerializationFailure.Program.Main(String[] args) in C:\code\MongoBulkWriteSerializationFailure\Program.cs:line 46
As it would be noted there are some control operations in the main program which demonstrate that data can be inserted in the target DB as well as data that contains the offending sub-string in the BulkWrite()
operation. I am testing against version 4.0.0
of MongoDB and using version 2.7.0
of the official Mongo C# driver.
Would anyone know what I could be missing in terms of preparing the data (e.g. escaping) prior to the BulkWrite()
operation? To be precise, applying another pair of '\' before the '\' solves the problem (so, Nick\\1
becomes Nick\\\\1
). But I have a feeling that this is a bit hacky as there could be other corner-cases that would break the serialization process. So, I am hoping that there is an 'escape function' or 'wrapper object' provided by the SDK that could be leveraged in order to address these serialization traps.
If you build the FilterDefinition
yourself in the Upsert function
like this:
public void Upsert(Person person)
{
var fiterBuilder = Builders<BsonDocument>.Filter;
var escapedFirstname = filter_builder.Eq("Firstname", person.Firstname);
var escapedLastname = filter_builder.Eq("Lastname", person.Lastname);
var filter = fiterBuilder.And(escapedFirstname, escapedLastname);
List<WriteModel<BsonDocument>> list_of_operations = new List<WriteModel<BsonDocument>>();
ReplaceOneModel<BsonDocument> write_model = new ReplaceOneModel<BsonDocument>(filter, person.ToBsonDocument());
write_model.IsUpsert = true;
list_of_operations.Add(write_model);
BulkWriteResult<BsonDocument> outcome = _collection.BulkWrite(list_of_operations, new BulkWriteOptions { IsOrdered = false });
System.Console.WriteLine($"Processed {outcome.ProcessedRequests.Count} item(s)");
}
It will escape the characters correctly.
And if you wish to know how the Driver does this you can see this happen here: https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Bson/IO/JsonScanner.cs#L33
User contributions licensed under CC BY-SA 3.0