简体   繁体   中英

Compare arrays and filter, using MongoDB aggregation

For my DB, I wrote the following pipeline:

let orders = await Order.aggregate(
        {
          $unwind: "$candidate",
        },
        {
          $lookup: {
            from: "groups",
            localField: "candidate.groupId",
            foreignField: "_id",
            as: "groupData",
          },
        },
        {
          $lookup: {
            from: "users",
            let: {
              id: "$candidate.groupId",
            },
            pipeline: [
              { $match: { groupId: { $ne: null } } },
              {
                $match: {
                  $expr: { $in: ["$$id", "$groupId"] },
                },
              },
              { $project: { name: 1, email: 1, _id: 1 } },
            ],
            as: "members",
          },
        },
        { $match: { "members._id": new ObjectId(req.userId) } },
        {
          $lookup: {
            from: "users",
            let: { ids: "$candidate.autonomousId" },
            pipeline: [
              {
                $match: {
                  $expr: { $in: ["$_id", "$$ids"] },
                },
              },
              { $project: { name: 1, email: 1, _id: 1 } },
            ],
            as: "candidate",
          },
        },
        {
          $project: {
            groupData: 1,
            members: 1,
            candidate: 1,
            stillAvailable: 1,
            _id: 0,
          },
        }
      ).toArray();

The output was the expected...

{ candidate:
    [ { _id: 601817dc2eeecd17db3a68f6,
        name: 'Maria' },
      { _id: 601817ef2eeecd17db3a68f7,
        name: 'Jose' } ],
   groupData:
    [ { _id: 606632403fffb851b8c41d12,
        name: 'Giraia' } ],
   members:
    [ { _id: 601817dc2eeecd17db3a68f6,
        name: 'Maria' },
      { _id: 601817ef2eeecd17db3a68f7,
        name: 'Jose' },
      { _id: 60182cbb2b654330d2458f89,
        name: 'Jonas'} ] } 

The last step in the pipeline would be to compare the arrays, filter which members were not candidates and add them to the array stillAvailable . I tried in many ways but I couldn't achieve my goal with aggregation. The only solution I could find was to process the result of the incomplete pipeline on my backend. The code is:

  orders.forEach(
    (order) =>
      (order.stillAvailable = order.members.filter(
        (autonomous) =>
          !order.candidate.some((el) => {
            return el._id.toString() === autonomous._id.toString();
          })
      ))
  );

With that, I reach the expected output...

 { candidate:
    [ { _id: 601817dc2eeecd17db3a68f6,
       name: 'Maria' },
      { _id: 601817ef2eeecd17db3a68f7,
       name: 'Jose' } ],
   groupData:
    [ { _id: 606632403fffb851b8c41d12,
        name: 'Giraia' ],
   members:
    [ { _id: 601817dc2eeecd17db3a68f6,
        name: 'Maria' },
      { _id: 601817ef2eeecd17db3a68f7,
        name: 'Jose' },
      { _id: 60182cbb2b654330d2458f89,
        name: 'Jonas' ],
   stillAvailable:
    [ { _id: 60182cbb2b654330d2458f89,
        name: 'Jonas' ] }

The problem is to better compartmentalize my code, it would be necessary to realize the last step (done with javascript on my backend) as one more step on the pipeline. Does anyone have an idea how to reach that?

After I wrote the question here, somehow the idea was better structured and I achieved the result, using $map and one more level of $lookup . I left the answer documented here in case someone falls into the same issue.

  let orders = await Order.aggregate(
    {
      $unwind: "$candidate",
    },
    {
      $lookup: {
        from: "groups",
        localField: "candidate.groupId",
        foreignField: "_id",
        as: "groupData",
      },
    },
    {
      $lookup: {
        from: "users",
        let: {
          id: "$candidate.groupId",
        },
        pipeline: [
          { $match: { groupId: { $ne: null } } },
          {
            $match: {
              $expr: { $in: ["$$id", "$groupId"] },
            },
          },
          { $project: { name: 1, email: 1, _id: 1 } },
        ],
        as: "members",
      },
    },
    { $match: { "members._id": new ObjectId(req.userId) } },
    {
      $lookup: {
        from: "users",
        let: { ids: "$candidate.autonomousId" },
        pipeline: [
          {
            $match: {
              $expr: { $in: ["$_id", "$$ids"] },
            },
          },
          { $project: { name: 1, email: 1, _id: 1 } },
        ],
        as: "candidate",
      },
    },
    {
      $project: {
        groupData: 1,
        members: 1,
        candidate: 1,
        _id: 0,
        stillAvailable: {
          $setDifference: [
            {
              $map: {
                input: "$members",
                as: "member",
                in: "$$member._id",
              },
            },
            {
              $map: {
                input: "$candidate",
                as: "el",
                in: "$$el._id",
              },
            },
          ],
        },
      },
    },
    {
      $lookup: {
        from: "users",
        let: {
          ids: "$stillAvailable",
        },
        pipeline: [
          {
            $match: {
              $expr: { $in: ["$_id", "$$ids"] },
            },
          },
          { $project: { name: 1, email: 1, _id: 1 } },
        ],
        as: "stillAvailable",
      },
    }
  ).toArray();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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