简体   繁体   English

聚合:根据子文档中的字段返回文档

[英]Aggregation: Return documents based on fields in a subdocument

I'm using an aggregation to return data via a lookup to build the links between documents.我正在使用聚合通过查找返回数据以建立文档之间的链接。

At the moment, the linking is working when User A creates links between their own assets to navigate.目前,当用户 A 在他们自己的资产之间创建链接以进行导航时,链接正在工作。

But if User A is viewing an asset that's been shared with them by User B and navigates to one that has a link to an asset that hasn't been shared with them, those are the documents I need to exclude from the results.但是,如果用户 A 正在查看用户 B 与他们共享的资产并导航到具有指向尚未与他们共享的资产的链接的资产,则这些是我需要从结果中排除的文档。

So, I need the documents for assets that have a document in attributes that contains my userId , or — as in the $match — the $_id of an attribute that's in the attributes array in assets .因此,我需要资产的文档,这些文档在属性中有一个包含我的userId的文档,或者——如在$match —— assetsattributes数组中的一个属性的$_id When an asset is shared with someone, a document in attributes is created.与某人共享资产时,会创建一个attributes文档。

The data for a Link is:链接的数据是:

{
  "_id": {
    "$oid": "63769c377615fe4cdb4995a6"
  },
  "userId": "620920aa9ddac2074a50472f",
  "toAsset": {
    "$oid": "63769c117615fe4cdb499515"
  },
  "fromAsset": {
    "$oid": "63769c067615fe4cdb4994d9"
  },
  "comment": "<p>Linking of Note 0001 to Note 0002.</p>",
  "createdAt": {
    "$date": {
      "$numberLong": "1668717623761"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1668717623761"
    }
  },
  "isEmbedded": false,
  "isActive": true,
  "__v": 0
}

The data for an Asset, as in toAsset and fromAsset, is:资产的数据,如 toAsset 和 fromAsset,是:

{
  "_id": {
    "$oid": "6377a8d834671794449f0dca"
  },
  "userId": "636b73f31527830f7bd7a47e",
  "folderId": "636b73f31527830f7bd7a482",
  "title": "Note that hasn't been shared",
  "note": "<p>Here's a Note that hasn't been shared.</p>",
  "typeOfAsset": "note",
  "createdAt": {
    "$date": {
      "$numberLong": "1668786392389"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1668786392389"
    }
  },
  "isActive": 3,
  "meta": [...],
  "preferences": [...],
  "sequence": 1,
  "tags": [],
  "attributes": [
    {
      "$oid": "6377a8d834671794449f0dc8"
    }
  ],
  "__v": 0
}

I'm using attributes to manage what assets have been shared with whom, and the data is:我正在使用属性来管理与谁共享了哪些资产,数据是:

{
  "_id": {
    "$oid": "6377a8d834671794449f0dc8"
  },
  "userId": "636b73f31527830f7bd7a47e",
  "numberOfViews": 2,
  "isFavourite": false,
  "isToRead": false,
  "typeOfAccess": "isOwner",
  "sharing": {
    "typeOfShare": "withUsers",
    "sharedWith": [],
    "segementsForUrl": []
  },
  "__v": 0
}

Now, the task here is to somehow how return the assets that have been shared, but after a bunch of different attempts (as per the code that's been commented out), I've so far failed.现在,这里的任务是以某种方式返回已共享的资产,但经过一系列不同的尝试(根据已注释掉的代码),我到目前为止都失败了。

The code is:代码是:

const match = {
  $match: {
    [args.directionOfLink]: new mongoose.Types.ObjectId(args.assetId)
  }
}

const project = {
  $project: {
    _id: 0,
    id: '$_id',
    userId: 1,
    [directionOfLink]: 1,
    comment: 1,
    createdAt: 1,
    updatedAt: 1,
    isActive: 1,
    score: {
      $meta: 'searchScore'
    }
  }
}

const lookup = {
  $lookup: {
    from: 'assets',
    localField: directionOfLink,
    foreignField: '_id',
    let: { attributesInAsset: '$attributes' },
    pipeline: [
      {
        $lookup: {
          from: 'attributes',
          as: 'attributes',
          pipeline: [{
            $match: {
              $expr: {
                $in: [ '$_id', '$$attributesInAsset' ]
                // $and: [
                  // { $eq: [ '$userId', context.body.variables.userId ] },
                  // { $in: [ '$typeOfAccess', ['isOwner', 'asAuthor', 'asReader'] ] },
                // ]
              }
            }
          }]
        }
      },
      {
        $project: {
          _id: 1,
          userId: 1,
          folderId: 1,
          title: 1,
          typeOfAsset: 1,
          attributes: 1,
          createdAt: 1,
          updatedAt: 1,
          isActive: 1
        }
      }
    ],
    as: directionOfLink
  }
}

Here, directionOfLink is either "toAsset" or "fromAsset".这里, directionOfLink是“toAsset”或“fromAsset”。

Any thoughts would be appreciated.任何想法将不胜感激。

As a non expert in MongoDB, it's possible this isn't the most performant approach, but at least it works:作为 MongoDB 的非专家,这可能不是最高效的方法,但至少它有效:

const lookup = {
  $lookup: {
    from: 'assets',
    localField: directionOfLink,
    foreignField: '_id',
    as: directionOfLink,
    pipeline: [
      {
        $lookup: {
          from: 'assets_attributes',
          as: 'attributesInAssets',
          pipeline: [
            {
              $match: {
                $expr: {
                  $and: [
                    { $eq: [ '$userId', context.body.variables.userId ] },
                    { $in: [ '$typeOfAccess', ['isOwner', 'asAuthor', 'asReader'] ] },
                  ]
                }
              }
            }
          ]
        }
      },
      {
        $unwind: '$attributesInAssets'
      },
      {
        $match: {
          $expr: {
            $in: [ '$attributesInAssets._id', '$attributes' ]
          }
        }
      },
      {
        $group: {
          _id: '$_id',
          userId: { $first: '$userId' },
          folderId: { $first: '$folderId' },
          title: { $first: '$title' },
          typeOfAsset: { $first: '$typeOfAsset' },
          createdAt: { $first: '$createdAt' },
          updatedAt: { $first: '$updatedAt' },
          isActive: { $first: '$isActive' },
          attributes: { $first: '$attributes' },
          attributesInAssets: {
            $push: '$attributesInAssets._id'
          }
        }
      },
      {
        $project: {
          _id: 1,
          userId: 1,
          folderId: 1,
          title: 1,
          typeOfAsset: 1,
          attributes: 1,
          attributesInAssets: 1,
          createdAt: 1,
          updatedAt: 1,
          isActive: 1
        }
      }
    ]
  }
}

const redact = {
  $redact: {
    $cond: {
      if: {
        $gt: [ {
          $size: `$${directionOfLink}`
        }, 0 ]
      },
      then: '$$KEEP',
      else: '$$PRUNE'
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM