Mongodb 如何对子文档数组使用$lookup
我有以下模式:Mongodb 如何对子文档数组使用$lookup,mongodb,mongoose,aggregation-framework,Mongodb,Mongoose,Aggregation Framework,我有以下模式: const chatbots = new Schema({ name: String, campaigns: [{ name: String, channels: [{ _id: String, name: String, budget: Number }] }] }); const chatbotusers = new Schema({ name: String, campaign_channel
const chatbots = new Schema({
name: String,
campaigns: [{
name: String,
channels: [{
_id: String,
name: String,
budget: Number
}]
}]
});
const chatbotusers = new Schema({
name: String,
campaign_channel: String
})
我需要得到一个活动列表,每个频道的用户总数。大概是这样的:
[
{
"name": "Campaign #1",
"channels": {
"_id": "eyRyZ1gD0",
"name": "Channel #1",
"users": 10
}
},
{
"name": "Campaign #1",
"channels": {
"_id": "tsKH7WxE",
"name": "Channel #2",
"users": 4
}
}
]
{
$lookup: {
from: "chatbotusers",
localField: "channels._id",
foreignField: "campaign_channel",
as: "users",
}
},
{
$project: {
name: "$name",
channels: {
$map: {
input: "$channels",
as: "channel",
in: {
_id: "$$channel._id",
name: "$$channel.name",
users: { $size: "$users" },
}
}
}
}
}
有什么想法吗
我得到的最远的结果是这样的:
[
{
"name": "Campaign #1",
"channels": {
"_id": "eyRyZ1gD0",
"name": "Channel #1",
"users": 10
}
},
{
"name": "Campaign #1",
"channels": {
"_id": "tsKH7WxE",
"name": "Channel #2",
"users": 4
}
}
]
{
$lookup: {
from: "chatbotusers",
localField: "channels._id",
foreignField: "campaign_channel",
as: "users",
}
},
{
$project: {
name: "$name",
channels: {
$map: {
input: "$channels",
as: "channel",
in: {
_id: "$$channel._id",
name: "$$channel.name",
users: { $size: "$users" },
}
}
}
}
}
但它计算的是该活动的用户数,而不是该频道的用户数
(很抱歉,如果问题标题不合适,我甚至不知道如何正确提问)您可以尝试以下查询:
db.chatbots.aggregate([
{
$lookup: {
from: "chatbotusers",
localField: "campaigns.channels._id",
foreignField: "campaign_channel",
as: "users"
}
},
{
$addFields: {
campaigns: {
$map: {
input: "$campaigns",
as: "eachCampaign",
in: {
$mergeObjects: ['$$eachCampaign', {
channels:
{
$reduce: {
input: "$$eachCampaign.channels",
initialValue: [],
in: {
$concatArrays: [
"$$value",
[
{
$mergeObjects: [
"$$this",
{
user: {
$size: {
$filter: {
input: "$users",
as: "e",
cond: {
$eq: [
"$$e.campaign_channel",
"$$this._id"
]
}
}
}
}
}
]
}
]
]
}
}
}
}]
}
}
}
}
},
{
$project: {
users: 0
}
}
])
注意:有多种方法可以做到这一点,但通过这种方法,我们正在处理来自聊天机器人集合的相同数量的文档,而不是通过执行$unwind
来分解文档,这在您拥有庞大数据集时可能会有所帮助
测试:
上面的查询应该可以满足您的需要,但在任何情况下,如果查询速度较慢或您认为需要增强,请点击此处:
{
user: {
$size: {
$filter: {
input: "$users", as: "e",
cond: {
$eq: [
"$$e.campaign_channel",
"$$this._id"
]
}
}
}
}
}
我们在每个活动中通过用户数组对每个频道进行迭代,因此在查找之后,您可以使用reduce
对用户进行一次迭代,以获得每个唯一的活动_频道的计数将此数据替换为用户数组,这样,您可以直接获得用户数。一般来说,上述查询的主要目的是保留原始文档结构,使用较少的阶段
或者,您可以使用此查询,该查询不保留原始文档结构(输出中的文档数量也可以超过集合中的文档数量),但可以执行您需要的操作:
db.chatbots.aggregate([
{
$unwind: "$campaigns"
},
{
$unwind: "$campaigns.channels"
},
{
$lookup: {
from: "chatbotusers",
localField: "campaigns.channels._id",
foreignField: "campaign_channel",
as: "users"
}
},
{
$addFields: {
"channels": "$campaigns.channels",
campaigns: "$campaigns.name"
}
},
{
$addFields: {
"channels.users": {
$size: "$users"
}
}
},
{
$project: {
users: 0
}
}
])
测试:如果您可以显示示例数据(简化,在查找后)和预期输出,例如使用mongoplayground.net、thanksThanks和@mickl,则会更容易。我不知道mongoplayground.net。非常感谢你给我这个超级完整的答案,@whoami。我最后选择了最后一个选项,因为我还需要其他一些东西,但我没有把它们包括在问题中。无论如何,非常感谢!