MongoDB中的BulkWrite操作失败,转义序列无效



我正在运行下面的代码,并收到后续错误:

代码:

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" });
}
}
}

错误:

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:codeMongoBulkWriteSerializationFailureProgram.cs:line 28
at MongoBulkWriteSerializationFailure.Program.Main(String[] args) in C:codeMongoBulkWriteSerializationFailureProgram.cs:line 46

应当注意,在主程序中存在一些控制操作,这些控制操作证明数据可以插入到目标DB中,以及在BulkWrite()操作中包含有问题的子串的数据。我正在测试MongoDB的4.0.0版本,并使用官方MongoC#驱动程序的2.7.0版本。

有人知道我在BulkWrite()操作之前准备数据(例如转义(时可能缺少什么吗?确切地说,在"\"之前应用另一对"\"可以解决问题(因此,Nick\1变成Nick\\1(。但我有一种感觉,这有点棘手,因为可能还有其他角落的情况会破坏序列化过程。因此,我希望SDK提供一个"转义函数"或"包装器对象",可以用来解决这些序列化陷阱。

如果您自己在Upsert函数中构建FilterDefinition像这样:

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)");
}

它将正确地转义字符。

如果你想知道司机是如何做到这一点的,你可以在这里看到:https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Bson/IO/JsonScanner.cs#L33

最新更新