9

Let's say we have a collection of documents like this one:

{
    "_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")
}

How do you extract only the documents where no item in the array $.carts have $.carts.closed set to true and $.carts.updatedon greater than $.updatedon minus 3 days ?

I know how to do find all the documents where no item in the array satisfy the condition $and: [closed: {$eq: true}, {updatedon: {$gt : new ISODate("2017-10-20T20:15:31Z")}}]

But how can you reference the parent element $.updatedon for the comparison?

In plain mongodb shell query language it would aleady be of help.

But I am actually accessing it using c# driver, so my query filter is like this:

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)
      )
);

How can I replace DateTime.Now.AddDays(-15) with a reference to the document root element updatedon?

2
  • Not sure if I'm missing something but, if you use f.updatedon while comparing c.updatedon doesn't that work? Commented Oct 28, 2017 at 7:57
  • @VivekAthalye nope, because f is not available on the right side of ElemMatch Commented Oct 29, 2017 at 22:20

2 Answers 2

2
+25

You can project the difference of carts.updatedon and updatedon and then filter out the results from this aggregation pipeline.

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 will filter out results more than 3 days difference documents.

I have just given the example of how you can use $subtract to find date difference and filter documents based on that.

Sign up to request clarification or add additional context in comments.

Comments

1

well I was in a similar situation few days back. I tackled it by using Jobject of Newtonsoft.Json. Create a function to return bool which actually process each document take it as input.

  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;

I hope this helps :) If you handling with any null values in those properties then please use Tryparse and out variable.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.