Rocky
Rocky

Reputation: 39

Mongo Db query over collections with same datastructure in c#

I want to query over more collections with the same datastructure and therefore i need to combine the collections.

I have collections like Measurements2016 ,2017 , 2018 and so on.

But if i retourn the collections i only have the first collection in the IMongoQuerable List.

At the moment the code is this.

public IMongoQueryable<MeasureDocument> MeasureDocuments()
{
  IMongoQueryable<MeasureDocument> tmpCollection = database.GetCollection<MeasureDocument>($"Measurements2014").AsQueryable();

  for (int i = 2015; i <= DateTime.Now.Year; i++)
  {
    tmpCollection.Union(this.database.GetCollection<MeasureDocument>($"Measurements{i}").AsQueryable());
  }

  return tmpCollection;
} 

Why is this not working?

Upvotes: 1

Views: 1205

Answers (1)

rytisk
rytisk

Reputation: 1529

You didn't understand how Linq's method Union works. It doesn't modify the collection on which you call it (in this case tmpCollection). Documentation says:

Produces the set union of two sequences by using the default equality comparer.

It has a return type of System.Collections.Generic.IEnumerable<TSource> which is the actual union of the two collections.

Your code should look like this:

tmpCollection = tmpCollection.Union(this.database.GetCollection<MeasureDocument>($"Measurements{i}").AsQueryable());

EDIT

It seems that IMongoQueryable doesn't support Union/Concat operations. Another option for you is to use fluent aggregation interface IAggregateFluent which supports collection unions. But you lose some flexibility because it doesn't have all the IMongoQueryable functionality.

With IAggregateFluent your code would look like this:

public IAggregateFluent<MeasureDocument> MeasureDocuments()
{
    var aggregation = database.GetCollection<MeasureDocument>($"Measurements2014").Aggregate();

    for (int i = 2015; i <= DateTime.Now.Year; i++)
    {
        aggregation = aggregation.UnionWith(database.GetCollection<MeasureDocument>($"Measurements{i}"));
    }

    return aggregation;
}

Then if you want to filter the aggregation you can do something like this:

var filter = Builders<MeasureDocument>
    .Filter
    .Eq(m => m.Field, "2018");

var documentsOf2018 = MeasureDocuments().Match(filter);

And in the end you can call ToEnumerable() to enumerate the documents:

foreach (var document in documentsOf2018.ToEnumerable())
{
    //...
}

Upvotes: 2

Related Questions