Как я могу запросить MongoDB для встроенного документа через драйвер C #?

2

Мне интересно, как можно запросить коллекцию MongoDB для встроенного документа (в массиве) через официальный С# драйвер версии 1.7? Запросив встроенный документ, я хочу, чтобы я хотел получить только встроенный документ, а не тот, который содержит его, AKA- проекцию.

Пример типа модели данных со встроенными документами, я спрашиваю:

// Library, contained in db.Libraries
{
    _id: 1,
    Categories: [{_id: 2, Name: "Classics", Books: [{_id: 3, Name: The Count of Monte Cristo}]}]
}

Проблема здесь заключалась в том, как запросить библиотечную коллекцию для объекта с _id 1 и одной из его книг с помощью _id 3 и вернуть только книгу. Это вообще возможно? Насколько я мог судить, это можно было бы сделать с помощью проекции в оболочке MongoDB.

Мой пример запроса состоял бы в том, чтобы запросить db.Libraries для книги с _id 3, содержащейся в библиотеке с _id 1. Возвращенная книга будет таким поддоку:

{_id: 3, Name: The Count of Monte Cristo}]}

Я рассмотрел вопрос Как получить встроенный документ с использованием официального драйвера С# для MongoDB? , но я не могу заставить принятый ответ работать для меня.

РЕДАКТИРОВАТЬ:

Теперь я вижу, что принятый ответ " Как получить встроенный документ с использованием официального драйвера С# для MongoDB"? работы, вид. Я не видел, что он выполняет итерации по каждому найденному документу, что эквивалентно этому:

var libraryCollection = new MongoCollection<Library>();
var refBook = new Book { Id = ObjectId.GenerateNewId().ToString(), Name = "The Count of Monte Cristo" };
libraryCollection.Insert(new Library { Id = ObjectId.GenerateNewId().ToString(), Categories = new[] { new Category { Books = new[] { refBook } } } });

MongoCursor<Library> libraries = libraryCollection.Find(new QueryDocument(
                    new Dictionary<string, object>
                        {
                            {"_id", new ObjectId()},
                        }
                    ));
Book book;
foreach (var library in libraries)
{
    book = library.Categories.SelectMany(c => c.Books).FirstOrDefault(b => b.Id == refBook.Id);
}

Однако это решение является спорным, поскольку оно извлекает целые документы библиотеки, а не только встроенный документ книги. Мне действительно нужно десериализовать только встроенную книгу, проекцию AKA.

  • 0
    Как вы можете ожидать, что кто-то вам поможет, если «Принятый ответ» в приведенной вами ссылке действительно показывает гораздо больше кода, чем вы предоставили. Пожалуйста, покажите весь соответствующий код, относящийся к вашему вопросу, в противном случае вы просите нас быть удивительными. Mind Readers
  • 0
    @DJKRAZE Не нужно быть грубым. Сама проблема должна быть понятна из предоставленной мною модели данных и того, к чему я обращаюсь (о чем я также говорил). Можете ли вы указать, какой код отсутствует, чтобы объяснить проблему?
Показать ещё 8 комментариев
Теги:
linq

1 ответ

3
Лучший ответ

Чтобы выполнить проекцию, в которой результирующий документ не просто фильтруется, но изменен, вам нужно использовать Aggregate вместо одного из методов Find например:

var result = collection.Aggregate(
    // Only include the document where _id = 1
    new BsonDocument {{"$match", new BsonDocument {{"_id", 1}}}},
    // 'Unwind' the Categories array by duplicating the docs, one per element.
    new BsonDocument {{"$unwind", "$Categories"}},
    // Now do the same for the Books array inside each Categories element.
    new BsonDocument {{"$unwind", "$Categories.Books"}},
    // Only include the resulting docs with a Book _id of 3
    new BsonDocument {{"$match", new BsonDocument {{"Categories.Books._id", 3}}}},
    // Reshape the document to bring the book attributes out to the top level 
    new BsonDocument {{"$project", new BsonDocument {
        {"_id", "$Categories.Books._id"},
        {"Name", "$Categories.Books.Name"}
    }}}
);

result.Response.toJson():

{"result": [{ "_id": 3.0, "Name": "The Count of Monte Cristo" }], "ok": 1.0 }
  • 0
    Спасибо! Решение довольно волосатое, но оно работает:]

Ещё вопросы

Сообщество Overcoder
Наверх
Меню