Найти, если элемент в массиве имеет значение, равное значению родительского элемента

Скажем, у нас есть набор документов, подобных этому:

{
    "_id" : ObjectId("591c54faf1c1f419a830b9cf"),
    "fingerprint" : "3121733676",
    "screewidth" : "1920",
    "carts" : [ 
        {
            "cartid" : 391796,
            "status" : "New",
            "cart_created" : ISODate("2017-05-17T13:50:37.388Z"),
            "closed" : false,
            "items" : [ 
                {
                    "brandid" : "PIR",
                    "cai" : "2259700"
                }
            ],
            "updatedon" : ISODate("2017-05-17T13:51:24.252Z")
        }, 
        {
            "cartid" : 422907,
            "status" : "New",
            "cart_created" : ISODate("2017-10-23T08:57:06.846Z"),
            "closed" : false,
            "items" : [ 
                {
                    "brandid" : "PIR",
                    "cai" : "IrHlNdGtLfBoTlKsJaRySnM195U"
                }
            ],
            "updatedon" : ISODate("2017-10-23T09:46:08.579Z")
        }
    ],
    "createdon" : ISODate("2016-11-08T10:29:55.120Z"),
    "updatedon" : ISODate("2017-10-23T09:46:29.486Z")
}

Как вы извлекаете только документы, в которых ни один элемент в массиве $.carts не имеет $.carts.closed, установленного в true и $.carts.updatedon больше $.updatedon минус 3 дня?

Я знаю, как найти все документы, в которых ни один элемент в массиве не удовлетворяет условию $and: [closed: {$eq: true}, {updatedon: {$gt : new ISODate("2017-10-20T20:15:31Z")}}]

Но как вы можете ссылаться на родительский элемент $.updatedon для сравнения?

В обычном языке запросов оболочки mongodb он может быть полезен.

Но я действительно обращаюсь к нему с помощью драйвера С#, поэтому мой фильтр запросов выглядит следующим образом:

FilterDefinition<_visitorData> filter;
filter = Builders<_visitorData>.Filter
  .Gte(f => f.updatedon, DateTime.Now.AddDays(-15));
filter = filter & (
  Builders<_visitorData>.Filter
    .Exists(f => f.carts, false) 
      | !Builders<_visitorData>.Filter.ElemMatch(f => 
        f.carts, c => c.closed && c.updatedon > DateTime.Now.AddDays(-15)
      )
);

Как заменить DateTime.Now.AddDays(-15) ссылкой на корневой элемент документа updatedon?

Ответ 1

Вы можете проецировать разницу carts.updatedon и updatedon, а затем отфильтровывать результаты из этого конвейера агрегации.

coll.aggregate([{'$unwind':'$carts'},
                {'$match':{'closed':{'$ne':true}}},
                {'$project':{'carts.cartid':1,'carts.status':1,'carts.cart_created':1,'carts.closed':1,'carts.items':1,'carts.updatedon':1,'updatedon':1,'diff':{'$subtract':['$carts.updatedon','$createdon']}}},
                {'$match': {'diff': {'$gte': 1000 * 60 * 60 * 24 * days}}}])

days = 3 отфильтровывает результаты более чем трехдневных разностных документов.

Я только что привел пример того, как вы можете использовать $subtract для определения разницы по дате и фильтрации документов на основе этого.

Ответ 2

Хорошо, что я был в подобной ситуации несколько дней назад. Я занялся этим, используя Jobject of Newtonsoft.Json. Создайте функцию для возврата bool, которая фактически обрабатывает каждый документ, принимая его как вход.

  Jobject jOb=Jobject.parse(<Your document string>);
  JArray jAr=JArray.Parse(jOb["carts"]);
  If(jOb["updateon"]=<Your Business Validation>)
  {
     foreach(var item in jAr)
       if(item["closed"]==<Your validation>){ return true}         

   }
 return false;

Надеюсь, это поможет:) Если вы обрабатываете любые нулевые значения в этих свойствах, то используйте переменную Tryparse и out.