Я пытаюсь добавить новый элемент массива во внешний массив схемы, который представляет собой сериализованный трехуровневый словарь с простым объектом скаляров в качестве конечного узла. Я могу написать новый документ на втором уровне этой структуры, но не на верхнем уровне. Пример схемы приведен ниже:
"_id" : ObjectId("5eb4b4a6c0a7d49190130fcb"),
"UserId" : UUID("46b42978-29c4-4521-9832-840cead6743e"),
"Vars" : [
{
"k" : "LRI39",
"v" : [
{
"k" : ISODate("2020-03-11T20:24:41.591Z"),
"v" : [
{
"k" : ISODate("2020-03-11T20:24:41.594Z"),
"v" : {
"_t" : "",
"Source" : 1,
"y" : "I",
"ObjValue" : 19
}
}
]
},
]
},
}
Элемент «Vars» содержит массив документов (внешний массив) пар ключ-значение со строковым ключом (k) и значением (v) представляет собой массив документов (средний массив) пар ключ-значение с датой в качестве ключа, а значение - это еще один словарь, который не является частью этого вопроса.
Этот код оболочки mon go работает ( для ясности, RC22 не существует как элемент массива Vars при его вызове)
db.threetier.update(
{ UserId: UUID("46b42978-29c4-4521-9832-840cead6743e")},
{ $push:
{ "Vars":
{ "k": "RC22",
"v" : [
{ "k" : ISODate("2020-04-02T10:11:12Z"),
"v" : [
{ "k" : ISODate("2020-04-02T10:11:12Z"),
"v" : {
"y": "I",
"Source" : 1,
"ObjValue" : "Flooby"
}
}
]
}
]
}
}
},
{ upsert: true }
);
Однако этот C# код не существует: я получаю InvalidCastException. gUserId - это Guid, который соответствует полю UserId документа.
NewItem = new BsonDocument()
{
{ "k", "RC22" },
{ "v", new BsonArray
{ new BsonDocument
{
{ "k", DateTime.Now },
{ "v", new BsonArray
{ new BsonDocument()
{
{ "k", DateTime.Now },
{ "v", new BsonDocument()
{
{ "y", "I" },
{ "Source", 1 },
{ "ObjValue", "Flooby" }
}
}
}
}
}
}
}
}
};
Filter = Builders<UserData>.Filter.Eq("UserId", gUserId);
// Create the update document
Update = Builders<UserData>.Update.Push("Vars", NewItem);
UpdateOptions Options = new UpdateOptions() { IsUpsert = true };
// Execute the update
UpdateResult urResult = _imcCollUserData.UpdateOne(Filter, Update, Options);
Теперь этот код C# отлично работает для обновления второго уровня структуры (LRI39 существует как элемент верхнего уровня array):
NewItem = new BsonDocument
{
{ "k", DateTime.Now },
{ "v", new BsonArray
{ new BsonDocument()
{
{ "k", DateTime.Now },
{ "v", new BsonDocument()
{
{ "y", "I" },
{ "Source", 1 },
{ "ObjValue", "Flooby" }
}
}
}
}
}
};
Filter = Builders<UserData>.Filter.Eq("UserId", gUserId) &
Builders<UserData>.Filter.Eq("Vars.k", "LRI39");
// Create the update document
Update = Builders<UserData>.Update.Push("Vars.$.v", NewItem);
UpdateOptions Options = new UpdateOptions() { IsUpsert = true };
// Execute the update
UpdateResult urResult = _imcCollUserData.UpdateOne(Filter, Update, Options);
Нет другой информации, кроме недопустимого исключения приведения (например, имени поля или чего-то еще), с трассировкой стека:
at MongoDB.Bson.Serialization.Serializers.SerializerBase`1.MongoDB.Bson.Serialization.IBsonSerializer.Serialize(BsonSerializationContext context, BsonSerializationArgs args, Object value)
at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Serialize(IBsonSerializer serializer, BsonSerializationContext context, Object value)
at MongoDB.Driver.PushUpdateDefinition`2.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(IClientSessionHandle session, 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 MongoDB.Driver.MongoCollectionBase`1.<>c__DisplayClass98_0.<UpdateOne>b__0(IEnumerable`1 requests, BulkWriteOptions bulkWriteOptions)
at MongoDB.Driver.MongoCollectionBase`1.UpdateOne(FilterDefinition`1 filter, UpdateDefinition`1 update, UpdateOptions options, Func`3 bulkWrite)
at MongoDB.Driver.MongoCollectionBase`1.UpdateOne(FilterDefinition`1 filter, UpdateDefinition`1 update, UpdateOptions options, CancellationToken cancellationToken)
Я посмотрел в журнале драйвера, и нет информации об этой ошибке, даже если ведение журнала установлено на подробный (5). Google очень мало возвращает для недопустимых приведений, большинство из которых связано с проблемами ObjectId. Я не могу отследить код сериализации, поэтому не уверен, что именно вызывает сбой. BsonDocument мне кажется точным воспроизведением работающей команды оболочки mon go. Я подозреваю, что спецификация целевого поля неверна, но использование Vars. $ Или Vars.0 возвращает ошибку «Сериализатор для поля 'Vars.0' [или Vars. $] Должен реализовать IBsonArraySerializer и предоставить информацию о сериализации элемента».