MongoDB $lookup on double nested array of objects

oymdgrw7  于 2023-11-17  发布在  Go
关注(0)|答案(1)|浏览(317)

我有一个数据模型,其中每个产品有许多变体,每个变体有许多修改。在数据库中,它看起来像这样:

  1. const mods = db.modifications.insertMany([
  2. {
  3. title: 'Modification #1',
  4. image: 'img1.png',
  5. },
  6. {
  7. title: 'Modification #2',
  8. image: 'img2.png',
  9. },
  10. {
  11. title: 'Modification #3',
  12. image: 'img3.png',
  13. },
  14. ])
  15. db.products.insertOne({
  16. slug: 'product1',
  17. title: 'Product #1',
  18. variants: [
  19. {
  20. size: 20,
  21. price: 200,
  22. modifications: [
  23. { id: mods.insertedIds[0], price: 10 },
  24. { id: mods.insertedIds[1], price: 15 },
  25. ],
  26. },
  27. {
  28. size: 30,
  29. price: 250,
  30. modifications: [
  31. { id: mods.insertedIds[0], price: 15 },
  32. { id: mods.insertedIds[2], price: 20 },
  33. ],
  34. },
  35. ],
  36. })

字符串
https://mongoplayground.net/p/6jmEv2Q2aZO
我想做的是

  1. db.products.aggregate([
  2. { $match: { slug: 'product1' } },
  3. // ?
  4. ])


得到这样的结果

  1. {
  2. slug: 'product1',
  3. title: 'Product #1',
  4. variants: [
  5. {
  6. size: 20,
  7. price: 200,
  8. modifications: [
  9. { _id: '…', title: 'Modification #1', image: '…', price: 10 },
  10. { _id: '…', title: 'Modification #2', image: '…', price: 15 },
  11. ],
  12. },
  13. {
  14. size: 30,
  15. price: 250,
  16. modifications: [
  17. { _id: '…', title: 'Modification #2', image: '…', price: 15 },
  18. { _id: '…', title: 'Modification #3', image: '…', price: 20 },
  19. ],
  20. },
  21. ],
  22. }


如何在MongoDB中实现?
我尝试了两次$unwind,然后$lookup

  1. db.products.aggregate([
  2. { $match: { slug: 'product1' } },
  3. { $unwind: '$variants' },
  4. { $unwind: '$variants.modifications' },
  5. {
  6. $lookup: {
  7. from: 'modifications',
  8. localField: 'variants.modifications.id',
  9. foreignField: '_id',
  10. let: { price: '$variants.modifications.price' },
  11. pipeline: [{ $addFields: { price: '$$price' } }],
  12. as: 'modifications',
  13. },
  14. },
  15. ])


但不知道如何将$group(?)数据返回。
还有a similar question with the working solution,在我的例子中,modifications数组不仅仅是一个id数组,它的元素(price字段)中有数据,我需要以某种方式将其包含在结果中。

4szc88ey

4szc88ey1#

您可以在没有$unwind阶段的情况下实现。

  1. $match
  2. $lookup-从 modifications 集合中获取匹配的文档,其中_id位于扁平化的modIdsvariants.modifications.id))中,并输出为modifications数组。
  3. $set-设置variants字段。
    3.1. $map-通过合并当前v(变量)对象和结果中的对象来迭代variants数组 3.1.1
    3.1.1. $map-通过迭代modifications数组,合并当前m(修改)对象和结果中的对象,对象包含modifications数组 3.1.1.1
    3.1.1.1. $first-从结果中获取第一个匹配元素 3.1.1.1.1.
    3.1.1.1.1. $filter-使用m.id从(根)modifications数组中筛选匹配文档。
  4. $unset-删除“modifications”和“variants.modifications.id“字段。
  1. db.products.aggregate([
  2. {
  3. "$match": {
  4. slug: "product1"
  5. }
  6. },
  7. {
  8. "$lookup": {
  9. "from": "modifications",
  10. "let": {
  11. modIds: {
  12. $reduce: {
  13. input: "$variants.modifications.id",
  14. initialValue: [],
  15. in: {
  16. $concatArrays: [
  17. "$$value",
  18. "$$this"
  19. ]
  20. }
  21. }
  22. }
  23. },
  24. "pipeline": [
  25. {
  26. "$match": {
  27. $expr: {
  28. $in: [
  29. "$_id",
  30. "$$modIds"
  31. ]
  32. }
  33. }
  34. }
  35. ],
  36. "as": "modifications"
  37. }
  38. },
  39. {
  40. $set: {
  41. variants: {
  42. $map: {
  43. input: "$variants",
  44. as: "v",
  45. in: {
  46. $mergeObjects: [
  47. "$$v",
  48. {
  49. modifications: {
  50. $map: {
  51. input: "$$v.modifications",
  52. as: "m",
  53. in: {
  54. $mergeObjects: [
  55. "$$m",
  56. {
  57. $first: {
  58. $filter: {
  59. input: "$modifications",
  60. cond: {
  61. $eq: [
  62. "$$this._id",
  63. "$$m.id"
  64. ]
  65. }
  66. }
  67. }
  68. }
  69. ]
  70. }
  71. }
  72. }
  73. }
  74. ]
  75. }
  76. }
  77. }
  78. }
  79. },
  80. {
  81. $unset: [
  82. "modifications",
  83. "variants.modifications.id"
  84. ]
  85. }
  86. ])

字符串
Demo @ Mongo Playground

展开查看全部

相关问题