如何在MongoDB聚合管道中引用列表映射音乐调值?
问题
我有一个音乐调列表:keys = ["C", "C♯/D♭", "D" , "D♯/E♭", "E", "F", "F♯/G♭", "G", "G♯/A♭", "A", "A♯/B♭", "B"]
同时有如下MongoDB聚合管道:
songsPipeline =[ { "$match" : { "userName": "stevendiffey" } }, { "$unwind" : "$songs"}, { "$project" : { "_id" : 0, "song" : "$songs.song", "artist" : "$songs.artist", "spotifyURI" : "$songs.spotifyURI", "image" : "$songs.image", "uuid" : "$songs.uuid", "key" : "$songs.key"}, } ]
我希望将输出中的key字段替换为上述keys列表中对应的音乐调。我已经通过以下步骤把原本是字符串的key转为整数:
{ "$set": { "key": { "$toInt": "$key" }} }
之后尝试用keys["key"]来映射,但出现错误:TypeError: list indices must be integers or slices, not str。请问如何实现该映射?理想情况下希望完全在聚合管道内完成,以便直接返回给Jinja模板。
解决方案
你不能直接在聚合管道里用Python列表的索引语法,因为MongoDB的聚合操作是在数据库端执行的,无法直接调用Python变量。要在聚合管道内完成映射,有两种常用方法:
方法一:使用$arrayElemAt操作符
把你的keys列表直接嵌入到聚合管道中,用$arrayElemAt根据转换后的整数key值获取对应的音乐调字符串。修改后的完整管道如下:
songsPipeline = [ { "$match": { "userName": "stevendiffey" } }, { "$unwind": "$songs" }, { "$project": { "_id": 0, "song": "$songs.song", "artist": "$songs.artist", "spotifyURI": "$songs.spotifyURI", "image": "$songs.image", "uuid": "$songs.uuid", "key": "$songs.key" } }, { "$set": { "key": { "$toInt": "$key" } } }, { "$set": { "key": { "$arrayElemAt": [ ["C", "C♯/D♭", "D", "D♯/E♭", "E", "F", "F♯/G♭", "G", "G♯/A♭", "A", "A♯/B♭", "B"], "$key" ] } } } ]
$arrayElemAt会接受一个数组和索引值,返回对应位置的元素,刚好匹配你的需求。
方法二:使用$switch操作符
如果你的key值可能存在超出0-11范围的情况,可以用$switch做分支匹配,同时处理异常情况:
songsPipeline = [ { "$match": { "userName": "stevendiffey" } }, { "$unwind": "$songs" }, { "$project": { "_id": 0, "song": "$songs.song", "artist": "$songs.artist", "spotifyURI": "$songs.spotifyURI", "image": "$songs.image", "uuid": "$songs.uuid", "key": "$songs.key" } }, { "$set": { "key": { "$toInt": "$key" } } }, { "$set": { "key": { "$switch": { "branches": [ { "case": { "$eq": ["$key", 0] }, "then": "C" }, { "case": { "$eq": ["$key", 1] }, "then": "C♯/D♭" }, { "case": { "$eq": ["$key", 2] }, "then": "D" }, { "case": { "$eq": ["$key", 3] }, "then": "D♯/E♭" }, { "case": { "$eq": ["$key", 4] }, "then": "E" }, { "case": { "$eq": ["$key", 5] }, "then": "F" }, { "case": { "$eq": ["$key", 6] }, "then": "F♯/G♭" }, { "case": { "$eq": ["$key", 7] }, "then": "G" }, { "case": { "$eq": ["$key", 8] }, "then": "G♯/A♭" }, { "case": { "$eq": ["$key", 9] }, "then": "A" }, { "case": { "$eq": ["$key", 10] }, "then": "A♯/B♭" }, { "case": { "$eq": ["$key", 11] }, "then": "B" } ], "default": "未知调式" # 处理超出范围的key值 } } } } ]
这种方法虽然代码更长,但能更灵活地处理异常情况,避免索引越界导致的错误。
内容的提问来源于stack exchange,提问作者Steven Diffey
相关产品推荐
相关产品推荐

