[英]MongoDB Linq OfType() on fields
This is my MongoDB document structure: 这是我的MongoDB文档结构:
{
string _id;
ObservableCollection<DataElement> PartData;
ObservableCollection<DataElement> SensorData;
...
other ObservableCollection<DataElement> fields
...
other types and fields
...
}
Is there any possibility to retrieve a concatenation of fields with the type ObservableCollection<DataElement>
? 是否有可能检索类型为
ObservableCollection<DataElement>
的字段的串联? Using LINQ I would do something like 使用LINQ,我会做类似的事情
var query = dbCollection
.AsQueryable()
.Select(x => new {
data = x
.OfType(typeof(ObservableCollection<DataElement>))
.SelectMany(x => x)
.ToList()
});
or alternatively 或者
data = x.Where(y => typeof(y) == typeof(ObservableCollection<DataElement>)
.SelectMany(x => x).ToList()
Unfortunately .Where()
and .OfType()
do not work on documents, only on queryables/lists, so is there another possibility to achieve this? 不幸的是
.Where()
和.OfType()
不适用于文档,仅适用于可查询的对象/列表,那么还有另一种方法可以实现此目的吗? The document structure must stay the same. 文档结构必须保持不变。
Edit: After dnickless answer I tried it with method 1b), which works pretty well for getting the fields thy way they are in the collection. 编辑:经过一丝不苟的回答后,我尝试使用方法1b)进行操作,该方法对于以您所希望的方式将字段放入集合中的效果很好。 Thank you!
谢谢!
Unfortunately it wasn't precisely what I was looking for, as I wanted to be all those fields with that specific type put together in one List, at it would be returned by the OfType
or Where(typeof)
statement. 不幸的是,这并不是我真正想要的,因为我希望将所有具有该特定类型的字段放到一个List中,这将由
OfType
或Where(typeof)
语句返回。
eg data = [x.PartData , x.SensorData, ...]
with data being an ObsverableCollection<DataElement>[]
, so that I can use SelectMany() on that to finally get the concatenation of all sequences. 例如
data = [x.PartData , x.SensorData, ...]
,数据是ObsverableCollection<DataElement>[]
,因此我可以在上面使用SelectMany()来最终获得所有序列的串联。
Sorry for asking the question unprecisely and not including the last step of doing a SelectMany()/Concat()
很抱歉无法精确地提出问题,并且不包括执行
SelectMany()/Concat()
的最后一步
Finally I found a solution doing this, but it doesn't seem very elegant to me, as it needs one concat()
for every element (and I have more of them) and it needs to make a new collection when finding a non-existing field: 最终,我找到了一个解决方案,但是对我来说似乎并不优雅,因为每个元素都需要一个
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()
In order to limit the fields returned you would need to use the MongoDB Projection feature in one way or the other. 为了限制返回的字段,您将需要以一种或另一种方式使用MongoDB Projection功能 。
There's a few alternatives depending on your specific requirements that I can think of: 根据您的具体要求,我可以考虑几种选择:
Option 1a (fairly static approach): Create a custom type with only the fields that you are interested in if you know them upfront. 选项1a (相当静态的方法):如果您事先知道您感兴趣的字段,则创建一个自定义类型。 Something like this:
像这样:
public class OnlyWhatWeAreInterestedIn
{
public ObservableCollection<DataElement> PartData { get; set; }
public ObservableCollection<DataElement> SensorData { get; set; }
// ...
}
Then you can query your Collection like that: 然后,您可以像这样查询您的收藏集:
var collection = new MongoClient().GetDatabase("test").GetCollection<OnlyWhatWeAreInterestedIn>("test");
var result = collection.Find(FilterDefinition<OnlyWhatWeAreInterestedIn>.Empty);
Using this approach you get a nicely typed result back without the need for custom projections. 使用这种方法,您可以得到很好的输入结果,而无需自定义投影。
Option 1b (still pretty static): A minor variation of Option 1a, just without a new explicit type but a projection stage instead to limit the returned fields. 选项1b (仍然非常静态):选项1a的一个细微变化,只是没有新的显式类型,而是一个投影级来限制返回的字段。 Kind of like that:
有点像:
var collection = new MongoClient().GetDatabase("test").GetCollection<Test>("test");
var result = collection.Find(FilterDefinition<Test>.Empty).Project(t => new { t.PartData, t.SensorData }).ToList();
Again, you get a nicely typed C# entity back that you can continue to operate on. 再次,您会得到一个类型正确的C#实体,您可以继续对其进行操作。
Option 2: Use some dark reflection magic in order to dynamically create a projection stage. 选项2:使用一些深色反射魔术来动态创建投影台。 Downside: You won't get a typed instance reflecting your properties but instead a BsonDocument so you will have to deal with that afterwards.
缺点:您将不会得到一个反映您的属性的类型化实例,而是一个BsonDocument,因此您随后将不得不对其进行处理。 Also, if you have any custom MongoDB mappings in place, you would need to add some code to deal with them.
另外,如果您有任何自定义的MongoDB映射,则需要添加一些代码来处理它们。
Here's the full example code: 这是完整的示例代码:
First, your entities: 首先,您的实体:
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
{
}
And then the test program: 然后测试程序:
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();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.