0

I'm very new to MongoDB, but have what I believed to be a very simple query.

I have a Protein object that inherits from IProtein (yes, my naming sucks)

public interface IProtein
{
    int Count { get; set; }
    DateTime Date { get; set; }
}

I want to return the FirstOrDefault from the collection based on a date comparison of the Date field of the protein object and Today

    public IProtein GetProteinForDay(DateTime day)
    {
        var collection = _db.GetCollection<IProtein>(DB_COLLECTION);

        var query = collection.AsQueryable<IProtein>()
                              .Where(p => p.Date == day.Date);

        var protein = query.FirstOrDefault();
        return protein;
    }

Unfortunately, I've gone through so many different variations of trying to match dates using MongoDB (some using Linq, some not) that I've completely lost focus on how far I got with each one.

This is my current code, it returns the error Unable to determine the serialization information for the expression: p.Date

What is wrong with my query (yes, it probably is something very simple) and how do I actually compare dates with a MongoDB / Linq query?

Dark Hippo
  • 1,255
  • 2
  • 15
  • 35
  • I think you may find your answer somewhere [here](https://stackoverflow.com/questions/40023067/unable-to-determine-the-serialization-information-for-expression-using-date) – Andrew Winterbotham Jul 10 '17 at 20:05
  • @AndrewWinterbotham I did work through that and several other answers on here, none of them seemed to work though. The above it what I settled on to ask the question – Dark Hippo Jul 11 '17 at 14:07

1 Answers1

4

Well, It's disappointing that .net DateTime doesn't work seamlessly with MongoDB driver. I believe support should be baked into driver.

Anyway you'll need to take couple of steps to make .net and MongoDB work together.

1) Decorate Date field in your interface with BsonDateTimeOptions attribute to tell MongoDB driver how to serialize .net DateTime. See BsonDateTimeOptions Documentation

Interface should looks like

public interface IProtein
{
    int Count { get; set; }

    [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
    DateTime Date { get; set; }
}

2) In your GetProteinForDay function, replace

var collection = _db.GetCollection<IProtein>(DB_COLLECTION);
var query = collection.AsQueryable<IProtein>()
                              .Where(p => p.Date == day.Date);

with

var collection = db.GetCollection<Protein>(DB_COLLECTION);
var query = collection.Find(p => p.Date == day); 

Notice that, I have replaced interface IProtein with concrete implementation of interface, in my case Protein.

Update: Full program is attached as reference.

Source document:

{
  _id: ObjectID('5964ebf315c46ab80b2c20f3),
  Count: 10,
  Date: '2017-07-11 00:00:00.000'
}

Test Program:

using System;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;

namespace mongoT
{
    public interface IProtein
    {
        ObjectId Id { get; set; }
        int Count { get; set; }

        [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
        DateTime Date { get; set; }
    }

    public class Protein : IProtein
    {
        public ObjectId Id { get; set; }
        public int Count { get; set; }
        public DateTime Date { get; set; }

        public override string ToString()
        {
            return $"{nameof(Id)}: {Id}, {nameof(Count)}: {Count}, {nameof(Date)}: {Date}";
        }
    }

    class Program
    {
        private static string DB = "ProteinsDB";
        private static string COLLECTION = "Proteins";

        static void Main(string[] args)
        {
            var result = GetProteinForDay(DateTime.Now.Date);
            Console.WriteLine(result);
        }

        public static IProtein GetProteinForDay(DateTime day)
        {
            var client = new MongoClient();
            var db = client.GetDatabase(DB);

            var collection = db.GetCollection<Protein>(COLLECTION);
            var query = collection.Find(p => p.Date == day.Date);

            var protein = query.FirstOrDefault();
            return protein;
        }
    }
}
Saleem
  • 8,728
  • 2
  • 20
  • 34
  • I feel like I should know this, but I'm now getting "Cannot convert lambda expression to type 'IMongoQuery' because it is not a delegate type" on "(p => p.Date == day)" – Dark Hippo Jul 11 '17 at 07:10
  • @DarkHippo, I couldn't reproduce error your reported. Please check if you have latest driver. I have updated my answer with sample solution. – Saleem Jul 11 '17 at 15:28
  • Great, thanks. I'll give it a shot when I'm back at my laptop – Dark Hippo Jul 12 '17 at 07:46
  • Yep, your sample code works fine. I guess I need to do some refactoring – Dark Hippo Jul 12 '17 at 20:41