Nurik
Nurik

Reputation: 33

How to filter only by year?

I want to find documents that matches to the given year.

I am using MongoDb.Driver, and currently i need a solution with this library.

int year = 2019;
var filter = Builders<CubesDataMdb>.Filter.Eq(x => x.DateOfCreation.Year, year);
var response = await Collection.Find(filter).FirstOrDefaultAsync();

Exception says: "Unable to determine the serialization information for x => x.DateOfCreation.Year." I expect the output to be one document which year is equal to my variable, no matter what is the other part of the date

Upvotes: 1

Views: 1666

Answers (2)

vikscool
vikscool

Reputation: 1313

As it is already been answered i am just going to provide an alternative approach for future reference(if anyone needs).

First the issue Unable to determine the serialization information for x => x.DateOfCreation.Year

The reason why you are getting this error is because the c# driver is translating the given linq statement:

int year = 2019;
var filter = Builders<CubesDataMdb>.Filter.Eq(x => x.DateOfCreation.Year, year);
var response = await Collection.Find(filter).FirstOrDefaultAsync();

To mongo shell script like:

db.Collection.find({"{document}{DateOfCreation}.Year":{$eq:2019}})

So, the Mongodb c# driver is not able to map it to any field as the field {document}{DateOfCreation}.Year does not exist in the class CubesDataMdb or in any of the documents stored in the Database(ps a simpler explanation would be that MongoDB does not support the linq converted syntax of field.Year).

So, an alternative approach apart from the answer provided by John.

Aggregation:

Use a ViewModel which have the same properties as the model CubesDataMdb apart from an additional property

public int Year { get; set; }

Then construct a $addFields stage to be used in the aggregation pipeline by extracting the year part from the object DateOfCreation using $year (by assuming the DateOfCreation have mongo dates and not string dates) as:

BsonDocument expressionString = new BsonDocument(new List<BsonElement>() {
    new BsonElement("Year", new BsonDocument(new BsonElement("$year", "$DateOfCreation"))),
});
BsonDocument addFieldsStageMongo = new BsonDocument(new BsonElement("$addFields", expressionMongo));
//adding the stage to the aggrigation pipeline
var response = await Collection
              .Aggregate()
              .AppendStage<BsonDocument>(addFieldsStageMongo)
              .Match(m=>m.Year == year)//using the filter on the newly added field of pipeline
              .FirstOrDefaultAsync();

The mongo shell equivalent query would be:

db.Collection.aggregate([
{$addFields:{
    Year:{$year:"$DateOfCreation"}
}},
{
    $match:{
        "Year":2019
    }
}
])

Upvotes: 1

ProgrammingLlama
ProgrammingLlama

Reputation: 38785

You have to search by range:

int year = 2019;
DateTime startDate = new DateTime(year, 1, 1);
DateTime endDate = new DateTime(year + 1, 1, 1);
var filter = Builders<CubesDataMdb>.Filter.Gte(x => x.DateOfCreation, startDate)
            & Builders<CubesDataMdb>.Filter.Lt(x => x.DateOfCreation, endDate);
var response = await Collection.Find(filter).FirstOrDefaultAsync();

So here we're making two dates: 2019/01/01 and 2020/01/01. Then we can search for all records whose dates are greater or equal to 2091/01/01 and less than 2020/01/01.

Upvotes: 2

Related Questions