#c# #.net #mongodb #mongodb-.net-driver
#c# #.net #mongodb #mongodb-.net-driver
Вопрос:
Я нахожусь в процессе обновления системы с устаревших драйверов Mongo на новые. У меня проблема со следующим запросом.
var orgsUnitReadModels = _readModelService.Queryable<OrganisationalUnitReadModel>()
.Where(x => locations.Contains(x.Id))
.Select(x => new AuditLocationItemViewModel
{
Id = x.Id,
Name = x.Name,
AuditRecordId = auditRecordId,
Type = type,
IsArchived = !x.IsVisible,
AuditStatus = auditStatus
}).ToList();
Выдает следующее сообщение об ошибке, которое я не понимаю. Я был бы благодарен за помощь, объясняющую, что это значит и как это исправить.
MongoDB.Driver.MongoCommandException: Ошибка агрегирования команды: спецификация плохой проекции, не удается исключить поля, отличные от _id, в проекции включения: { Id: «$_id», Name: «$Name», AuditRecordId: BinData (3, 5797FCCCA90C8644B4CB84FED4236D4B), Тип: 0, Архивировано: { $not: [ «$isVisible» ] }, AuditStatus: 2, _id: 0 }.’
Ответ №1:
В этом примере оператор выбора LINQ преобразуется в $ project в MongoDB. Обычно вы используете 0
(или false
) для исключения полей и 1
или true
для включения полей в конечный набор результатов. Конечно, вы также можете использовать синтаксис dollar для ссылки на существующие поля, что происходит, например, для Name
.
Проблема в том, что вы также пытаетесь включить некоторые значения констант в памяти как часть проекции. К сожалению, один из них ( type
) равен 0
, который интерпретируется так, как если бы вы хотели исключить вызываемое поле Type
из результата конвейера.
Из-за этой неоднозначности MongoDB ввел оператор $literal, и вы можете попробовать следующий синтаксис в оболочке Mongo:
db.col.aggregate([{ $project: { _id: 0, Id: 1, Name: 1, Type: { $literal: 0 } } }])
Он будет возвращен 0
как постоянное значение, как вы ожидаете. В документации по драйверу MongoDB .NET здесь упоминается literal, но, похоже, это работает только для строк.
Есть несколько способов решить вашу проблему, я думаю, что проще всего сначала запустить более простую .Select
инструкцию, а затем использовать .ToList()
, чтобы убедиться, что запрос выполнен. Как только это будет сделано, вы можете запустить другой файл в памяти, .Select()
чтобы создать свой OrganisationalUnitReadModel
:
.Where(x => locations.Contains(x.Id))
.Select(x => new { x.Id, x.Name, x.IsVisible }).ToList()
.Select(x => new AuditLocationItemViewModel
{
Id = x.Id,
Name = x.Name,
Type = type,
IsArchived = !x.IsVisible,
AuditStatus = auditStatus
}).ToList();