2014-10-06 3 views
0

Есть ли способ обновить сложный документ MongoDB с C# с помощью JSON? Например, предположим, что у меня есть следующий документ:Обновление документа MongoDB с использованием JSON

{ 
    "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 похожа на первую, минус все поля и элементы массива, которые не изменяются, за исключением того, что одно поле в любом массиве рассматривается, что однозначно идентифицирует этот индекс. В этом случае поле «возраст» включено, поскольку оно обновляется с заданным значением. Поле «title» указывается для определения правильного элемента массива при поиске обновляемого поля. Также может быть еще больше поддокументов и массивов, и формат не является статическим (он может измениться позднее). Это просто упрощенный пример.

Возможно ли передать что-то подобное этой функции и обновить правильное поле таким образом? Есть ли что-то, по крайней мере, похожее на это, поэтому я могу просто перейти в JSON для обновления?

Причина, по которой я хочу сделать это так, а не посредством более простых средств, заключается в том, что я хочу отслеживать историю изменений в документах, и если я хочу вернуться к более ранней версии, я хочу, чтобы простой способ сделать это, чтобы справиться с этим уровнем сложности.

UPDATE:

У меня есть несколько уточнений, чтобы сделать. В этом конкретном случае я не могу предсказать, какие изменения необходимо будет внести. В любое время можно было бы внести изменения в любое поле, и это поле могло быть где угодно в документе, возможно на верхнем уровне, или в нескольких вложенных вложенных документах/массивах. Данные, с которыми мы имеем дело, - это отдельная сторона, которая может ее использовать и модифицировать по своему усмотрению, поэтому мы не можем контролировать то, что они предпочитают делать с ней. Кроме того, нет фиксированной схемы. Другая сторона может добавлять новые поля, включая новые поддокументы или массивы, или удалять их.

Причина, по которой я задаю этот вопрос, заключается в том, что я хотел бы сохранить историю изменений в документах таким образом, чтобы я мог вернуться к более раннему снимку документа, применив изменения в обратном порядке. В этом случае изменение возраста от 20 до 21 вернет документ в более старое состояние (предполагая, что кто-то перепутал с возрастом заранее и сделал его 20, и я хотел исправить его до 21). Поскольку кто-то может внести какие-либо изменения в систему, в том числе в базовую структуру самих данных, я не могу просто придумать свою собственную схему или жесткий код - решение, которое изменяет определенные поля с использованием этой конкретной схемы.

В этом примере изменение возраста от 20 до 21 было бы из записи в истории, структура которой я не мог предсказать заранее. Поэтому я ищу эффективное решение для применения непредсказуемого обновления к документу, учитывая упрощенное представление JSON об изменениях, которые необходимо внести.

Я также открыт для альтернатив, которые не связаны с JSON, если они достаточно эффективны. Я воспитывал JSON, потому что я полагал, что, если MongoDB использует JSON для структурирования документов, это будет иметь наибольший смысл и, возможно, превосходит что-то вроде строковых манипуляций. Другая альтернатива, которую я рассмотрел, будет заключаться в том, чтобы сохранить изменение с помощью какой-то пользовательской точечной нотации, например: readingList[ISBN:3513531513551].author.age=21"

Это потребовало бы, чтобы я создал пользовательскую функцию для интерпретации строки и превратил ее во что-то полезное, хотя, t звучит как лучшее решение.

ответ

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 
       } 
     }] 
} 

// вам нужен запрос, который возвращает основной документ по идентификатору, например, когда вы у вас есть основной документ, который вы можете запросить в том, который вы хотите изменить в списке, и попробуйте его в varibale, скажем, readItem, затем внесите необходимые изменения и после этого вы можете обновлять только нужные поля, используя set и onle element в массиве с использованием «$» что-то вроде:

readItem.title = "some new title"; 
readItem.age++; 
var update = MongoDB.Driver.Builders.Update.Set("readingList.$", BsonDocumentWrapper.Create(readItem)); 
Update<Book>(query, update); 
0

На самом деле я бы не советовал вам выбирать такую ​​модель данных, потому что по моему опыту она станет довольно грязной. Тем не менее, у вас могут быть очень специфические требования, которые могут заставить вас иметь эту и только эту модель данных.

Я бы создал две коллекции: лица и чтения списков.

человек будет выглядеть так:

{ 
    "id":"123", 
    "name": "John Smith", 
    "age": 35 
} 

и readinglists будут выглядеть так (обратите внимание, что он имеет соединение естественный идентификатор):

{ 
    "_id": { "personid":"123", "title": "Title1"}, 
    "ISBN": 6246246426724, 
    "author": 
      { 
       "name": "James Johnson", 
       "age": 40 
      } 
} 

Затем вы можете легко обновить readinglist:

var query = Query.EQ("_id", new BsonDocument(new BsonElement[]{ new BsonElement("personid":"123"), BsonElement("title":"Title1")})); 

readingListCollection.Update(query, Update.Set("author.age": 22)); 
0

В режиме данных вам необходимо знать индекс массива второго документа. Лучше моделировать атрибут readList как карту. В следующем примере я использовал 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# нотацию для этого, но должно быть прямо вперед.

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" 
     } 
    } 
] 

}

Я просто использовал состояние как имя автора Сэм Хилл и выполнить ниже запрос в 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"));