这是我的MongoDB文档结构:
{
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()
不能在文档上工作,只能在可查询/列表上工作,那么还有另一种可能吗?文档结构必须保持不变。
修改 在无知的回答之后,我尝试了方法1b),这非常适合以他们在集合中的方式获取字段。谢谢!
不幸的是,它并不是我想要的,因为我希望将所有那些特定类型的字段放在一个列表中,它将由OfType
或{{返回1}}陈述。
e.g。数据为Where(typeof)
的{{1}},以便我可以使用SelectMany()来最终获得所有序列的连接。
很抱歉不准确地提出问题而不包括做data = [x.PartData , x.SensorData, ...]
的最后一步
最后我找到了一个解决方案,但它对我来说似乎并不优雅,因为它需要一个ObsverableCollection<DataElement>[]
来表示每一个元素(而且我有更多的元素)它需要制作一个查找不存在的字段时的新集合:
SelectMany()/Concat()
答案 0 :(得分: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();
}
}