我正在尝试创建以下方法来从子数组中检索ObjectId数组。
GetStorageLocationIds()
GetStorageRoomIds(ObjectId locationId)
GetStorageSectionIds(ObjectId locationId, ObjectId roomId)
GetStorageShelfIds(ObjectId locationId, ObjectId roomId, ObjectId sectionId)
GetStorageSlotIds(ObjectId locationId, ObjectId roomId, ObjectId sectionId, ObjectId shelfId)
(这可能并不困难,因为它已经是ObjectId的数组)
每个方法应返回一个IEnumerable<ObjectId>
,其中包含适当数组的id
属性的数组。我意识到我可以只获取每个列表的整个文档,但是我更喜欢使用MongoDB c#驱动程序的更有效,更优雅的解决方案。
这是一个示例文档:
{
"_id" : ObjectId("5cb2271a4bd93c0dec4db163"),
...
"StorageRooms" : [
{
"_id" : ObjectId("5cb49adc36ad6719bf947103"),
...
"StorageSections" : [ ]
},
{
"_id" : ObjectId("5cb49afa36ad6719bf947106"),
...
"StorageSections" : [
{
"_id" : ObjectId("5cb49bb8c40cd319cb2511ae"),
...
"StorageShelves" : [ ]
},
{
"_id" : ObjectId("5cb49bb8c40cd319cb2511af"),
...
"StorageShelves" : [
{
"_id" : ObjectId("5cb49bfe8d259019d9207f48"),
...
"StorageSlotIds" : [ ]
},
{
"_id" : ObjectId("5cb49bfe8d259019d9207f49"),
...
"StorageSlotIds" : [ ]
}
]
}
]
},
{
"_id" : ObjectId("5cb49afa36ad6719bf947107"),
...
"StorageSections" : [ ]
}
]
}
上述方法应使用上面的示例文档作为输入数据,返回以下数组。 (假设它是集合中唯一的一个):
GetStorageLocationIds()
-> ["5cb2271a4bd93c0dec4db163"]
GetStorageRoomIds("5cb2271a4bd93c0dec4db163")
-> ["5cb49adc36ad6719bf947103,"5cb49afa36ad6719bf947106", "5cb49afa36ad6719bf947107"]
GetStorageSectionIds("5cb49afa36ad6719bf947106")
-> ["5cb49bb8c40cd319cb2511ae","5cb49bb8c40cd319cb2511af"]
等...
到目前为止,我已经能够编写第一个:GetStorageLocationIds
。这是代码,似乎运行良好:
public async Task<IEnumerable<ObjectId>> GetAllDocumentIdsAsync(string database, string collection,
CancellationToken cancellationToken)
{
return (await _mongoContext.MongoClient.GetDatabase(database).GetCollection<T>(collection)
.Find(new BsonDocument())
.Project(new BsonDocument {{"_id", 1}})
.ToListAsync(cancellationToken)).Select(x => x[0].AsObjectId);
}
关于下一个,我尝试使用ProjectionDefinition
,但所做的只是返回文档id
而不是id
数组中的每个StorageRooms
。 / p>
public async Task<IEnumerable<ObjectId>> GetStorageRoomIdsAsync(ObjectId id, CancellationToken cancellationToken)
{
var filter = Builders<StorageLocation>.Filter.And(
Builders<StorageLocation>.Filter.Where(location => location.Id == id));
var projectionDefinition = Builders<StorageLocation>.Projection.Include(location => location.StorageRooms);
var projectionResult = await ProjectAsync(filter, projectionDefinition, cancellationToken);
return projectionResult.Select(x => x[0].AsObjectId);
}
在尝试使用聚合后,我相信它将与Unwind
一起使用,但是我对如何正确地在c#中实现这一点迷失了。预先感谢您的帮助。
编辑注意:为简便起见,在本问题中可互换使用ObjectId和字符串。我将AutoMapper用于我的实际项目
来自micki的答案适用于GetStorageRoomIds
。我现在正尝试将以下代码用于GetStorageSectionIds
,但出现错误:
return from location in AsQueryable()
where location.Id == id
from room in location.StorageRooms
where room.Id == roomId
from section in room.StorageSections
select section.Id;
错误为here
答案 0 :(得分:1)
对于这样的查询,您可以在AsQueryable()
上运行IMongoCollection
,然后使用LINQ语法,如下所示:
var storageRoomIds = from location in Col.AsQueryable()
where location.Id == locationId
from room in location.StorageRooms
select room.Id;
您也可以打开MongoDB profiler来查看它会被翻译成
"pipeline" : [
{
"$match" : {
"_id" : ObjectId("5cb2271a4bd93c0dec4db163")
}
},
{
"$unwind" : "$StorageRooms"
},
{
"$project" : {
"_id" : "$StorageRooms._id"
}
}
],
所以您既有简单的C#代码又有高效的MongoDB查询
编辑:对于以下级别,您仍然可以使用LINQ语法:
var rooms = from location in Col.AsQueryable()
where location.Id == locationId
from room in location.StorageRooms
select new
{
roomId = room.Id,
storageIds = room.StorageSections.Select(x => x.Id)
};
var storageIds = from room in rooms
where room.roomId == roomId
from storageId in room.storageIds
select storageId;
var result = storageIds.ToList();
这被翻译成:
"pipeline" : [
{
"$match" : {
"_id" : ObjectId("5cb2271a4bd93c0dec4db163")
}
},
{
"$unwind" : "$StorageRooms"
},
{
"$project" : {
"roomId" : "$StorageRooms._id",
"storageIds" : "$StorageRooms.StorageSections._id",
"_id" : 0
}
},
{
"$match" : {
"roomId" : ObjectId("5cb49afa36ad6719bf947106")
}
},
{
"$unwind" : "$storageIds"
},
{
"$project" : {
"storageIds" : "$storageIds",
"_id" : 0
}
}
],