MongoDB C # — фильтр для поиска объекта по contiditon во вложенном массиве

#c# #.net #mongodb #mongodb.driver

#c# #.net #mongodb #mongodb.driver

Вопрос:

У меня возникла проблема с созданием фильтра для получения объекта по условию во вложенном массиве.

Мои модели:

 public class ProductPriceInStore
{
    [BsonId]
    public ObjectId Id { get; set; }

    public ObjectId store { get; set; }

    public ObjectId product { get; set; }

    public string measurementUnit { get; set; }

    public IList<ProductPrices> prices { get; set; }
}

 public class ProductPrices
{
    public double? actualPrice { get; set; }
  
    public double? originalPrice { get; set; }
}
 

Что я хочу сделать, так это найти весь ProductPriceInStore, который содержит ProductPrice с actualPrice больше, чем originalPrice

Я использую nugget MongoDB.Driver 2.7.3 в своем проекте

Комментарии:

1. Посмотрите ElemMatch .

2. Я пытался использовать его следующим образом: var filter = Builders<ProductPriceInStore> . Фильтр. elemMatch(y => y.prices, x => x.actualPrice > x.originalPrice); но это дало мне ошибку ‘Неподдерживаемый фильтр: ({document}{actualPrice}> {document}{originalPrice}). Мне нужно будет подробнее изучить elementMatch

Ответ №1:

 db.ProductPriceInStore.find({$expr:{$gt:["$prices.actualPrice", "$prices.originalPrice"]}})
 

Ответ №2:

Вы можете использовать Linq query selector: если у вас есть список ProductPriceInStore, так что вы можете сделать:

 ProductPriceInStoreList.Where(item => item.prices.Where(p => p.actualPrice  > p.originalPrice   ))
 

Комментарии:

1. у меня это как IMongoCollection. Я могу каким — то образом получить доступ к linq с помощью . Найдите метод ant, тогда я не знаю, как его определить, обычно это заканчивается ошибкой, что драйвер не может перевести команду. И я не могу загрузить эту коллекцию в память — я имею в виду с помощью «.ToList», потому что в этой коллекции более 5 000 000 записей…

Ответ №3:

вы можете получить желаемый результат с помощью следующего конвейера агрегации, $elemMatch который нельзя использовать для сравнения значений полей во вложенных объектах (afaik).

 db.ProductPriceInStore.aggregate(
[
    {
        $set: {
            prices: {
                $filter: {
                    input: "$prices",
                    cond: { $gt: ["$$this.actualPrice", "$$this.originalPrice"] }
                }
            }
        }
    },
    {
        $match: {
            prices: { $gt: [0, { $size: "$prices" }] }
        }
    }
])
 

однако это было бы неэффективно. гораздо лучшим подходом было бы сохранить логическое свойство IsGreaterThanOriginalPrice во время создания / сохранения вложенных элементов, и в этом случае вы можете легко использовать ElemMatch его без особых хлопот.