有没有办法将异构数组指定为架构属性,它可以包含ObjectIds和字符串?我希望得到以下内容:
var GameSchema = new mongoose.schema({
players: {
type: [<UserModel reference|IP address/socket ID/what have you>]
}
我自己管理的Mixed
类型是唯一的选项吗?我跑过discriminators,看起来有点有希望,但看起来它只适用于子文档而不是对其他模式的引用。当然,我可以只有一个UserModel
引用并创建一个UserModel
来存储IP地址或我用来识别它们的任何内容,但这似乎可以很快得到很大的帮助在空间方面的控制(我遇到的每个IP的模型听起来很糟糕)。
编辑:
示例:
游戏中有一个登录用户,三个匿名用户,文档应如下所示:
{ players: [ ObjectId("5fd88ea85...."), "192.0.0.1", "192.1.1.1", "192.2.2.1"] }
理想情况下,这将填充到:
{ players: [ UserModel(id: ..., name: ...), "192.0.0.1", "192.1.1.1", "192.2.2.1"] }
编辑:
我决定采用不同的方式:不是混合类型,而是区分不同的属性。像这样:
players: [
{
user: <object reference>,
sessionID: <string>,
color: {
type: String
},
...other properties...
}
]
我有一个验证器,可确保只为给定条目填充user
或sessionID
中的一个。在某些方面,这更复杂,但它确实消除了进行这种条件填充的需要,并且在迭代它们时确定每个条目的类型。我没有尝试过任何答案,但看起来很有希望。
答案 0 :(得分:0)
如果您满意使用Mixed
或至少某些不适用于.populate()
的方案,那么您可以将“加入”责任转移到“服务器”而不是使用{{ 3}} MongoDB的功能和一些花哨的匹配。
对我来说,如果我有一个"games"
这样的收藏文件:
{
"_id" : ObjectId("5933723c886d193061b99459"),
"players" : [
ObjectId("5933723c886d193061b99458"),
"10.1.1.1",
"10.1.1.2"
],
"__v" : 0
}
然后我将语句发送到服务器以“加入”"users"
收集数据,其中ObjectId
存在,如下所示:
Game.aggregate([
{ "$addFields": {
"users": {
"$filter": {
"input": "$players",
"as": "p",
"cond": { "$gt": [ "$$p", {} ] }
}
}
}},
{ "$lookup": {
"from": "users",
"localField": "users",
"foreignField": "_id",
"as": "users"
}},
{ "$project": {
"players": {
"$map": {
"input": "$players",
"as": "p",
"in": {
"$cond": {
"if": { "$gt": [ "$$p", {} ] },
"then": {
"$arrayElemAt": [
{ "$filter": {
"input": "$users",
"as": "u",
"cond": { "$eq": [ "$$u._id", "$$p" ] }
}},
0
]
},
"else": "$$p"
}
}
}
}
}}
])
在将用户对象加入时,将结果显示为:
{
"_id" : ObjectId("5933723c886d193061b99459"),
"players" : [
{
"_id" : ObjectId("5933723c886d193061b99458"),
"name" : "Bill",
"__v" : 0
},
"10.1.1.1",
"10.1.1.2"
]
}
所以当考虑"players"
数组中的条目时,“花哨”部分真的依赖于这个逻辑语句:
"$filter": {
"input": "$players",
"as": "p",
"cond": { "$gt": [ "$$p", {} ] }
}
这是如何工作的,对于MongoDB,ObjectId
实际上所有BSON类型都有$lookup
。在这种情况下,数据在ObjectId
和String
之间“混合”,则“字符串”值被视为“小于”“BSON对象”的值,ObjectId
值“大于”。
这允许您将源代码中的ObjectId
值分隔到它们自己的列表中。根据该列表,您specific sort precedence执行“加入”以获取其他集合中的对象。
为了将它们放回去,我正在使用$map
来“转置”原始"players"
的每个元素,其中找到匹配的ObjectId
与相关对象。另一种方法是“拆分”两种类型,在Users
和“字符串”之间执行$lookup
和$lookup
。但这不会维持原始数组顺序,因此$concatArrays
可能更合适。
我将补充说明,通过类似地过滤"players"
数组的内容以仅包含ObjectId
值,然后调用“”,可以在“客户端”操作中应用相同的基本过程。从初始查询的响应“内部”模型“$map
的形式”。文档显示了这种使用形式的一个示例,在此网站上的一些答案之前,可以使用mongoose进行“嵌套填充”。
这里的另一个观点是.populate()
本身早在.populate()
聚合管道运算符出现之前就作为mongoose方法存在,并且是MongoDB本身无法执行的时候的解决方案任何形式的“加入”。因此,操作确实是“客户端”作为仿真,并且实际上只执行您自己发布语句时不需要注意的其他查询。
因此,在现代场景中通常应该使用“服务器”功能,并避免多个查询所涉及的开销以获得结果。