MongoDB如果其他集合中存在字段/引用,则从汇总中排除文档

时间:2020-05-19 19:59:31

标签: mongodb mongoose aggregation-framework

const sellerSchema = Schema(
  {
    name: String,
    url:String
  }
const productSchema = Schema(
  {
    title: String,
    sellerUrl:String
  }

以下查询将从所有产品返回唯一的sellerUrl

context.Product.aggregate([
        {
          $group: {
            _id: "$sellerUrl",
          }
        }
      ]);

但是我也想从汇总中排除已经保存的卖方。因此,如果url == sellerUrl汇总必须排除该卖方。 请帮助我

1 个答案:

答案 0 :(得分:2)

您可以尝试以下查询:

db.product.aggregate([
    {
      $group: {
        _id: "", /** group on no condition & push all unique `sellerUrl` to sellerUrls array */
        sellerUrls: { $addToSet: "$sellerUrl" }
      }
    },
    {
      $lookup: {
        from: "seller",
        let: { sellerUrls: "$sellerUrls" }, // creating local variable
        pipeline: [
          { $group: { _id: "", urls: { $addToSet: "$url" } } }, /** group on no condition & push all unique `url` to urls array */
          { $project: { _id: 0, uniqueAndNotInSellerColl: { $setDifference: [ "$$sellerUrls", "$urls" ] } } } // get difference between two arrays
        ],
        as: "data" // As we're grouping will always be one doc/element in an array
      }
    },
    /** Create a new root doc from getting first element(though it will have only one) from `data` array */
    {
      $replaceRoot: { newRoot: { $arrayElemAt: [ "$data", 0 ] } }
    }
  ])

测试: mongoplayground

更新:

由于您需要product集合中的其他几个字段,而不仅仅是sellerUrl字段,请尝试以下查询:

db.product.aggregate([
    {
      $group: {
        _id: "$sellerUrl",
        docs: { $push: { title: "$title" } } // We're only retrieving `title` field from `product` docs, if every field is needed use `$$ROOT`
      }
    },
    /** We've used basic `lookup` stage, use this if you've only few matching docs from `seller` collection
     *  If you've a lot of matching docs for each `_id` (sellerUrl), 
     *  then instead of getting entire `seller` doc (which is not needed) use `lookup` with aggregation pipeline & 
     *  just get `_id`'s of seller docs for better performace refer previous query
     */
    {
      $lookup: {
        from: "seller",
        localField: "_id",
        foreignField: "url",
        as: "sellerDocs"
      }
    },
    /** match will retain only docs which doesn't have a matching doc in seller collection */
    {
      $match: { sellerDocs: [] }
    },
    {
      $project: { sellerDocs: 0 }
    }
  ])

测试: mongoplayground