Home > Software engineering >  How do you use a filter query with Google's Civil.Date package in MongoDB?
How do you use a filter query with Google's Civil.Date package in MongoDB?

Time:11-02

Google's civil package is simple - it's aim is to represent a single day of the year without respect to time or location. This is useful for things like birthdays where it's the same all over the world - even though time is different all over the world.

The main struct is:

type Date struct {
    Year  int        // Year (e.g., 2014).
    Month time.Month // Month of the year (January = 1, ...).
    Day   int        // Day of the month, starting at 1.
}

And it gets represented in MongoDB as an object with 3 integer values:

# golang definition
occurredOn civil.Date `bson:"occurredOn"`
...

# mongodb definition
occurredOn Object
year       2022
month      4
day        2

This leads to weirdness if you want to query. For instance I don't think standard $gt / $lt queries will work as 2022-4-2 is lexicographically greater than 2022-10-20 but is an earlier date and I believe mongoDB can do a best-case scenario for comparing objects against each other but that also adds internal complexity to the query. Essentially it's far more complicated than comparing two instances of time.Time against each other. So what's the easiest way to do it?

CodePudding user response:

As far as I can tell there are four edge cases to cover:

  • Same date but different year
  • Same date but different month
  • Same date but different day
  • Some combination of different year/month/day

Here's the function I came up with to return a mongoDB query to check for a civil.Date strictly greater than another civil.Date. Apologies for the weird formatting but this is what the go fmt spit out:

func occurredOnGTQueryTest(date civil.Date) bson.M {
    return bson.M{"$or": bson.A{
        bson.M{"occurredOn.year": bson.M{"$gt": date.Year}}, // happens in the next year

        bson.M{"occurredOn.year": bson.M{"$gte": date.Year},
            "occurredOn.month": bson.M{"$gt": date.Month}}, // happens in the next month

        bson.M{"occurredOn.year": bson.M{"$gte": date.Year},
            "occurredOn.month": bson.M{"$gte": date.Month},
            "occurredOn.day":   bson.M{"$gt": date.Day}}, // happens in the next day
    },
    }
}

CodePudding user response:

I think there's no implementation to serialize type of civil.Date in mongo bson pacakge. (There's no function MarshalBinary)

Maybe, it has to be changed to time.Time package for better solution because it has the implementation in any serialization such as bson, json or xml and even in google datastore.

However if the type of civil.Date is the desired one then you should query and compare the field one by one ranging from year, month and day. And you have to consider to update or modified the indexes of the collection.

  • Related