有没有办法使用JSON从C#更新复杂的MongoDB文档?例如,假设我有以下文档:
{
"name": "John Smith",
"age": 35,
"readingList":
[{
"title": "Title1",
"ISBN": 6246246426724,
"author":
{
"name": "James Johnson",
"age": 40
}
},
{
"title": "Title2",
"ISBN": 3513531513551,
"author":
{
"name": "Sam Hill",
"age": 20
}
}]
}
现在我想将第二本书的作者(Sam Hill)的年龄从20更新为21.假设我有以下JSON表示:
{
"readingList":
[
{
"title": "Title2",
"author":
{
"age": 21
}
}]
}
基本上第二个JSON字符串就像第一个字符串一样,减去所有不会改变的字段和数组元素,除了正在查看的任何数组中的一个字段唯一标识该索引。在这种情况下,"年龄"包含字段,因为它是使用给定值更新的。 "标题"在搜索要更新的字段时,给出字段以定位正确的数组元素。可能还有更多的子文档和数组要经过,格式不是静态的(可能会在以后更改)。这只是一个简化的例子。
是否可以将类似的内容传递给某个函数并以这种方式更新正确的字段?有没有至少与此类似的东西,所以我可以传入一些JSON来进行更新?
我希望这样做的原因,而不是通过简单的方式,是因为我想跟踪文档更改的历史记录,如果我想回溯到早期版本,我想要一个简单的这样做的方法可以处理这种复杂程度。
更新:
我做了一些澄清。在这种特殊情况下,我无法预测需要进行哪些更改。可以随时对任何字段进行更改,该字段可以位于文档中的任何位置,可能位于顶层,也可以位于多个嵌套的子文档/数组中。我们正在处理的数据是针对可以使用它并随意修改它的单独一方,因此我们无法控制他们选择使用它做什么。此外,没有固定的架构。另一方可以添加新字段,包括新的子文档或数组,或删除它们。
我提出这个问题的原因是因为我想以这样的方式存储文档更改的历史记录,以便通过反向应用更改来恢复文档的旧快照。在这种情况下,将年龄从20更改为21将使文档恢复到较旧的状态(假设某人事先与年龄相混并使其成为20,我想将其修复为21)。由于有人可以对系统做出任何改变,包括对数据本身的底层结构,我不能提出自己的架构,或硬编码使用这种特定架构更改特定字段的解决方案。
在这个例子中,年龄从20岁到21岁的变化将来自历史记录,其结构我无法事先预测。因此,我正在寻找一种有效的解决方案,在给定更改的简化JSON表示的情况下对文档应用不可预测的更新。
如果他们相当有效,我也愿意接触不涉及JSON的替代品。我提出了JSON,因为我认为,鉴于MongoDB使用JSON来构建文档,它将最有意义,并且可能优于字符串操作。我考虑的另一个替代方案是使用某种自定义点表示法来存储更改,如下所示:readingList[ISBN:3513531513551].author.age=21"
这需要我创建一个自定义函数来解释字符串并将其转换为有用的东西,因此它听起来不是最好的解决方案。
答案 0 :(得分:0)
你可以查询你的主文件让我们假设你的主要收藏品被命名为“书籍”这是结构:
{
"id":"123",
"name": "John Smith",
"age": 35,
"readingList":
[{
"title": "Title1",
"ISBN": 6246246426724,
"author":
{
"name": "James Johnson",
"age": 40
}
},
{
"title": "Title2",
"ISBN": 3513531513551,
"author":
{
"name": "Sam Hill",
"age": 20
}
}]
}
//您需要一个按id返回主文档的查询,例如,当您拥有主文档时,您可以在列表中查询要修改的主文档并将其分配给varibale让我们说readItem,然后执行你需要的修改,之后你可以使用set更新你需要的字段,并使用“$”来代替数组中的元素:
readItem.title = "some new title";
readItem.age++;
var update = MongoDB.Driver.Builders.Update.Set("readingList.$", BsonDocumentWrapper.Create(readItem));
Update<Book>(query, update);
答案 1 :(得分:0)
实际上我不建议你选择这种数据模型,因为根据我的经验,它会变得相当混乱。尽管如此,您可能还有一些非常具体的要求可能会迫使您只拥有此数据模型。
我会创建两个集合:人员和阅读列表。
人们看起来像是:{
"id":"123",
"name": "John Smith",
"age": 35
}
和阅读列表看起来像(注意它有一个复合自然id):
{
"_id": { "personid":"123", "title": "Title1"},
"ISBN": 6246246426724,
"author":
{
"name": "James Johnson",
"age": 40
}
}
然后您可以轻松更新阅读列表:
var query = Query.EQ("_id", new BsonDocument(new BsonElement[]{ new BsonElement("personid":"123"), BsonElement("title":"Title1")}));
readingListCollection.Update(query, Update.Set("author.age": 22));
答案 2 :(得分:0)
在数据模式下,您需要知道第二个文档的数组索引。最好将readingList属性建模为地图。在下面的示例中,我使用isbn作为映射键:
{
"id":"123",
"name":"John Smith",
"age":35,
"readingList":{
"6246246426724":{
"title":"Title1",
"ISBN":6246246426724,
"author":{
"name":"James Johnson",
"age":40
}
},
"3513531513551":{
"title":"Title2",
"ISBN":3513531513551,
"author":{
"name":"Sam Hill",
"age":20
}
}
}
}
在此数据模型中,您可以直接访问第二本书。例如dot notation:
db.authors.update(
{ item: "123" },
{ $set: { "readingList.3513531513551.author.age": 22 } }
)
不幸的是,我确实知道C#表示法,但应该是直截了当的。
答案 3 :(得分:0)
你好朋友我在JSON文档下面使用
{
"_id" : ObjectId("56a99c121f25cc3a3c709151"),
"name" : "John Smith",
"age" : 35,
"readingList" : [
{
"title" : "Title1",
"ISBN" : NumberLong(6246246426724),
"author" : {
"name" : "James Johnson",
"age" : 40
}
},
{
"title" : "Title2",
"ISBN" : NumberLong(3513531513551),
"author" : {
"name" : "Sam Hill",
"age" : "25"
}
}
]
}
我刚使用条件作为作者姓名是Sam Hill并在C#及其工作中执行以下查询。
IMongoQuery query = Query.And(Query.EQ("name", "John Smith"), Query.EQ("readingList.author.name", "Sam Hill"));
var result =collection.Update(query,
MongoDB.Driver.Builders.Update.Set("readingList.$.author.age", "21"));