如何使用嵌套数组MongoDB c#将对象数组映射到对象属性数组

问题描述 投票:1回答:1

我正在尝试创建以下方法以从子数组中检索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

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用于实际项目

Edit 2:

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

c# arrays mongodb nested mongodb-.net-driver
1个回答
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
        }
    }
],
© www.soinside.com 2019 - 2024. All rights reserved.