2017-06-19 22 views
0

這是我的MongoDB的文檔結構:MongoDB中的LINQ OfType()上的字段

{ 
    string _id; 
    ObservableCollection<DataElement> PartData; 
    ObservableCollection<DataElement> SensorData; 
    ... 
    other ObservableCollection<DataElement> fields 
    ... 
    other types and fields 
    ... 
} 

是否有可能檢索與類型ObservableCollection<DataElement>場的串聯?使用LINQ我會做類似

var query = dbCollection 
    .AsQueryable() 
    .Select(x => new { 
    data = x 
     .OfType(typeof(ObservableCollection<DataElement>)) 
     .SelectMany(x => x) 
     .ToList() 
    }); 

或可替代

data = x.Where(y => typeof(y) == typeof(ObservableCollection<DataElement>) 
.SelectMany(x => x).ToList() 

不幸的是.Where().OfType()不處理文檔,只有queryables /列表,所以是有其他方式來實現這一目標?文檔結構必須保持不變。

編輯: 後dnickless答案我有方法1B),這非常有效的讓字段你的路,他們都在收集試了一下。謝謝!

遺憾的是它不正是我一直在尋找,因爲我想是與特定類型一起放在一個列表,它會被OfTypeWhere(typeof)語句返回的所有領域。

例如data = [x.PartData , x.SensorData, ...]與數據是ObsverableCollection<DataElement>[],以便我可以使用SelectMany()來最終獲得所有序列的連接。

對不起,問的問題unprecisely不包括做一個SelectMany()/Concat()

最後,我找到了一個解決方案這樣做的最後一步,但它似乎並不很優雅對我來說,因爲它需要爲每一個concat()元素(和我有更多的人),它需要找到一個不存在的領域時,使一個新的集合:

query.Select(x => new 
      { 
      part = x.PartData ?? new ObservableCollection<DataElement>(), 
      sensor = x.SensorData ?? new ObservableCollection<DataElement>(), 
      } 
    ) 
     .Select(x => new 
      { 
      dataElements = x.part.Concat(x.sensor)         
      } 
    ).ToList() 

回答

0

爲了限制領域返回你需要以某種方式使用MongoDB Projection feature或另一個。

有根據您的具體要求,我能想到的幾個備選方案:

方案1A(相當靜態的方法):創建只有您有興趣,如果你知道他們的字段的自定義類型前期。事情是這樣的:

public class OnlyWhatWeAreInterestedIn 
{ 
    public ObservableCollection<DataElement> PartData { get; set; } 
    public ObservableCollection<DataElement> SensorData { get; set; } 
    // ... 
} 

然後你就可以查詢您的收藏這樣的:

var collection = new MongoClient().GetDatabase("test").GetCollection<OnlyWhatWeAreInterestedIn>("test"); 
var result = collection.Find(FilterDefinition<OnlyWhatWeAreInterestedIn>.Empty); 

使用這種方法,你會得到一個很好的結果輸入回,而不需要自定義投影。

可能性1b(仍然相當靜態):方案1A的微小變化,只是沒有新的明確的類型,但投影階段,而不是限制返回的字段。類似於:

var collection = new MongoClient().GetDatabase("test").GetCollection<Test>("test"); 
var result = collection.Find(FilterDefinition<Test>.Empty).Project(t => new { t.PartData, t.SensorData }).ToList(); 

再次,您將得到一個很好的類型化的C#實體,您可以繼續操作。

選項2:使用一些暗反射魔術來動態創建投影舞臺。下行:你不會得到一個反映你的屬性的類型實例,而是一個BsonDocument,所以你將不得不在後面處理。另外,如果你有任何自定義的MongoDB映射,你需要添加一些代碼來處理它們。

下面是完整的示例代碼:

首先,你的實體:

public class Test 
{ 
    string _id; 
    public ObservableCollection<DataElement> PartData { get; set; } 
    public ObservableCollection<DataElement> SensorData { get; set; } 
    // just to have one additional property that will not be part of the returned document 
    public string TestString { get; set; } 
} 

public class DataElement 
{ 
} 

然後測試程序:

public class Program 
{ 
    static void Main(string[] args) 
    { 
     var collection = new MongoClient().GetDatabase("test").GetCollection<Test>("test"); 

     // insert test record 
     collection.InsertOne(
      new Test 
      { 
       PartData = new ObservableCollection<DataElement>(
        new ObservableCollection<DataElement> 
        { 
         new DataElement(), 
         new DataElement() 
        }), 
       SensorData = new ObservableCollection<DataElement>(
        new ObservableCollection<DataElement> 
        { 
         new DataElement(), 
         new DataElement() 
        }), 
       TestString = "SomeString" 
      }); 

     // here, we use reflection to find the relevant properties 
     var allPropertiesThatWeAreLookingFor = typeof(Test).GetProperties().Where(p => typeof(ObservableCollection<DataElement>).IsAssignableFrom(p.PropertyType)); 

     // create a string of all properties that we are interested in with a ":1" appended so MongoDB will return these fields only 
     // in our example, this will look like 
     // "PartData:1,SensorData:1" 
     var mongoDbProjection = string.Join(",", allPropertiesThatWeAreLookingFor.Select(p => $"{p.Name}:1")); 

     // we do not want MongoDB to return the _id field because it's not of the selected type but would be returned by default otherwise 
     mongoDbProjection += ",_id:0"; 

     var result = collection.Find(FilterDefinition<Test>.Empty).Project($"{{{mongoDbProjection}}}").ToList(); 

     Console.ReadLine(); 
    } 
}