猫鼬:过滤文档并处理嵌套数组

时间:2019-03-19 09:24:42

标签: mongodb mongoose

我有一个图像模式,该图像模式引用了一个类别模式,并且一个嵌套的数组包含一个带有两个字段(用户,createdAt)的对象

我正在尝试按类别查询架构,并向查询中的每个图像添加两个自定义字段。

这是虚拟字段的解决方案:

总数:所有嵌套属性的计数

schema.virtual("totalLikes").get(function() {
  return this.likes.length;
});

canLike :检查ID为“ 5c8f9e676ed4356b1de3eaa1”的用户是否包含在嵌套数组中。如果包含用户,则应返回false,否则返回true

schema.virtual("canLike").get(function() {
  return !this.likes.find(like => {
    return like.user === "5c8f9e676ed4356b1de3eaa1";
  });
});

在sql中,这将是一个简单的子查询,但我无法在Mongoose中使用它。

模式:

import mongoose from "mongoose";

const model = new mongoose.Schema(
{
  category: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "Category"
  },
  likes: [{
    user: {
      type: String,
      required: true
    },
    createdAt: {
      type: Date,
      required: true
    }
  }]
})

这是示例文档:

[{
    category:5c90a0777952597cda9e9c8d,
    likes: [
        {
        _id: "5c90a4c79906507dac54e764",
        user: "5c8f9e676ed4356b1de3eaa1",
        createdAt:"2019-03-19T08:13:59.250+00:00"
        }
    ]
},
{
    category:5c90a0777952597cda9e9c8d,
    likes: [
        {
        _id: "5c90a4c79906507dac54e764",
        user: "5c8f9e676ed4356b1dw223332",
        createdAt:"2019-03-19T08:13:59.250+00:00"
        },
        {
        _id: "5c90a4c79906507dac54e764",
        user: "5c8f9e676ed4356b1d8498933",
        createdAt:"2019-03-19T08:13:59.250+00:00"
        }
    ]
}]

这是它的外观:

 [{
    category:5c90a0777952597cda9e9c8d,
    likes: [
        {
        _id: "5c90a4c79906507dac54e764",
        user: "5c8f9e676ed4356b1de3eaa1",
        createdAt:"2019-03-19T08:13:59.250+00:00"
        }
    ],
    totalLikes: 1,
    canLike: false
},

 {
    category:5c90a0777952597cda9e9c8d,
    likes: [
        {
        _id: "5c90a4c79906507dac54e764",
        user: "5c8f9e676ed4356b1dw223332",
        createdAt:"2019-03-19T08:13:59.250+00:00"
        },
        {
        _id: "5c90a4c79906507dac54e764",
        user: "5c8f9e676ed4356b1d8498933",
        createdAt:"2019-03-19T08:13:59.250+00:00"
        }
    ],
    totalLikes: 2,
    canLike: true
 }]

这是我尝试过的:

解析器:

1)在猫鼬通话中尝试-失败

const resources = await model.aggregate([
      { $match: {category: "5c90a0777952597cda9e9c8d"},
      $addFields: {
        totalLikes: {
          $size: {
            $filter: {
              input: "$likes",
              as: "el",
              cond: "$$el.user"
            }
          }
        }
      },
      $addFields: {
        canLike: {
            $match: {
              'likes.user':"5c8f9e676ed4356b1de3eaa1"
            }              
        }
      }
    }
      ])

2)试图在数据库调用后更改它-可以,但不是首选解决方案

model.where({ competition: "5c90a0777952597cda9e9c8d"  }).exec(function (err, records) {


    resources = records.map(resource => {

    resource.likes = resource.likes ? resource.likes: []

    const included = resource.likes.find(like => {
      return like.user === "5c8f9e676ed4356b1de3eaa1";
    });

    resource.set('totalLikes', resource.likes.length, {strict: false});
    resource.set('canLike', !included, {strict: false});

   return resource
  });
})

有人知道我如何在运行时做到这一点吗? THX

1 个答案:

答案 0 :(得分:0)

您可以使用聚合来实现

Model.aggregate()
.addFields({ // map likes so that it can result to array of ids
    likesMap: {
        $map: {
            input: "$likes",
            as: "like",
            in: "$$like.user"
        }
    }   
})
.addFields({ // check if the id is present in likesMap
    canLike: {
        $cond: [
            {
                $in: ["5c8f9e676ed4356b1de3eaa1", "$likesMap"]
            },
            true,
            false
        ]
    },
    totalLikes: {
        $size: "$likes"
    }
})
.project({ // remove likesMap
    likesMap: 0,
})