【问题标题】:How can i iterate mongoose returned documents array in loop using mongoose?如何使用 mongoose 在循环中迭代 mongoose 返回的文档数组?
【发布时间】:2019-11-21 21:32:15
【问题描述】:

我有一个node.js(express based) 服务器,其中有一个function,它返回所有users。这是函数。

export async function findAllUser() {
  let users = await User.find({}).exec()
  return users
}

在我的node.js 应用程序中,我有两个models(schema)UsersReferrals,就像这样。

var User = mongoose.model(
    "users",
    new Schema({
        first_name: String,
        last_name: String,
        name: String,
        email: String,
        password: String,
        roleId: { type: Number, default: 0 },
        country: String,
        token: String,
        createdAt: String,
        updatedAt: String,
        tempToken: String,
        verificationCode: String,
        fbUserId: String,
        isFbUser: { type: Boolean, default: false },
        isActive: { type: Boolean, default: true },
        isEmailVerified: { type: Boolean, default: false },
        rememberme: Boolean,
    }, {
        toJSON: { virtuals: true },
        toObject: { virtuals: true }
    })
);

User.virtual("referrals", {
    ref: "referralLinks",
    foreignField: "userId",
    localField: "_id"
});
export var ReferralLink = mongoose.model(
    "referralLinks",
    new Schema({
        referral_link: String,
        referral_code: String,
        isLink: Number,
        offer_name: String,
        offer_desc: String,
        user_email: String,
        companyId: { type: Schema.Types.ObjectId, ref: 'companies' },
        addedByAdmin: { type: Boolean, default: true },
        number_of_clicks: Number,
        referral_country: String,
        link_status: String,
        categoryId: { type: Schema.Types.ObjectId, ref: 'categories' },
        number_of_clicks: { type: Number, default: 0 },
        createdAt: String,
        updatedAt: String,
        userId: { type: Schema.Types.ObjectId, ref: 'users' }
    })
);

我有一个单独的api.route.js 文件,我在其中获得了所有用户这样的路由

router.get("/", log, getAllUsers);

我的api.controller.js 文件我有getAllUsers 这样的文件

export async function getAllUsers(req, res) {
try {
    let Users = await findAllUser()
    if (Users) {
        generateResponse(true, "All Users fetched", Users, res)
    } else {
        generateResponse(false, "No Users found", null, res)
    }
 } catch (err) {
    generateResponse(false, 'Error occured, 404 not found!', err, res)
 }
}

在我的api.handler.js 文件中,我有findAllUser 这样的函数

export async function findAllUser() {
    let users = await User.find({}).populate("referrals").exec()
    return users
}

单个用户可以拥有多个Referrals。但不幸的是,我在Users 文档中没有“推荐人”参考_id。现在,我想让所有用户拥有各自的Referrals

我正确获取了所有users,但对于每个用户,我还想获取他们各自的所有referrals。因此,由于猫鼬查找的异步性质,我绝对不能使用forforEach 循环。那么我应该使用什么来代替forforEach 循环呢?

我想要的结果

 results = [
            {
                first_name : "Fahad",
                last_name : "subzwari",
                email : "fahadsubzwari@gmail.com",
                password : "***",
                referrals  : [
                    {
                        //referral object 1
                    },
                    {
                        //referral object 2 ... 
                    }
                ]
            },
            {
                first_name : "Alex",
                last_name : "Hales",
                email : "alex@gmail.com",
                password : "***",
                referrals  : [
                    {
                        //referral object 1
                    },
                    {
                        //referral object 2 ... 
                    },
                    {
                        //referral object 3 ... 
                    }
                ]
            },
        ]

【问题讨论】:

  • 您说“我在用户中没有 'Referrals' 参考 _id”。推荐人是否参考了用户?你需要一些方法来链接它们。
  • 你可以为用户和推荐模式添加代码吗?一些示例文档也可以。
  • @JamesTrickey 是的,我在Referrals 中有Users _id
  • @JamesTrickey 我已经更新了我的问题,请看

标签: javascript node.js mongodb express mongoose


【解决方案1】:

为了能够访问来自用户的推荐,您需要使用virtual populate

所以你的 userSchema 必须是这样的:

const userSchema = new Schema(
  {
    first_name: String,
    last_name: String,
    name: String,
    email: String,
    password: String,
    roleId: { type: Number, default: 0 },
    country: String,
    token: String,
    createdAt: String,
    updatedAt: String,
    tempToken: String,
    verificationCode: String,
    fbUserId: String,
    isFbUser: { type: Boolean, default: false },
    isActive: { type: Boolean, default: true },
    isEmailVerified: { type: Boolean, default: false },
    rememberme: Boolean
  },
  {
    toJSON: { virtuals: true },
    toObject: { virtuals: true }
  }
);

// Virtual populate
userSchema.virtual("referrals", {
  ref: "referralLinks",
  foreignField: "userId",
  localField: "_id"
});

var User = mongoose.model("users", userSchema);

现在您可以使用此路由访问用户的推荐:

router.get("/", async (req, res) => {

  const result = await User.find({}).populate("referrals");

  res.send(result);
});

结果会是这样的:(为简单起见,我排除了一些字段)

[
    {
        "_id": "5dd6819201419f5930d02334",
        "name": "User 1",
        "email": "user1@gmail.com",
        "password": "123123",
        "__v": 0,
        "referrals": [
            {
                "_id": "5dd6829831b95a6b2cd58fca",
                "referral_link": "referral_link 1",
                "userId": "5dd6819201419f5930d02334",
                "__v": 0
            },
            {
                "_id": "5dd682a031b95a6b2cd58fcb",
                "referral_link": "referral_link 2",
                "userId": "5dd6819201419f5930d02334",
                "__v": 0
            }
        ],
        "id": "5dd6819201419f5930d02334"
    },
    {
        "_id": "5dd681a101419f5930d02335",
        "name": "User 2",
        "email": "user2@gmail.com",
        "password": "123123",
        "__v": 0,
        "referrals": [
            {
                "_id": "5dd682a731b95a6b2cd58fcc",
                "referral_link": "referral_link 3",
                "userId": "5dd681a101419f5930d02335",
                "__v": 0
            }
        ],
        "id": "5dd681a101419f5930d02335"
    }
]

更新:

以下是您的项目设置步骤:

api.handler.js:

exports.findAllUser = async function() {
  console.log("api handler inside");
  let users = await User.find({})
    .populate("referrals")
    .exec();
  console.log("in handler: ", users);
  return users;
};

api.controller.js:

const handler = require("./api.handler");

exports.getAllUsers = async function(req, res) {
  console.log("userController.getAllUsers");
  try {
    let Users = await handler.findAllUser();
    if (Users) {
      return res.send(Users);
      generateResponse(true, "All Users fetched", Users, res);
    } else {
      generateResponse(false, "No Users found", null, res);
    }
  } catch (err) {
    generateResponse(false, "Error occured, 404 not found!", err, res);
  }
};

api.route.js

const apiController = require("../controllers/api.controller");
router.get("/",  log, apiController.getAllUsers);

【讨论】:

  • 是否有必要将这个{ toJSON: { virtuals: true }, toObject: { virtuals: true } } 放入我的User 架构中?
  • @FahadHassanSubzwari 是的,它必须在模式中。但这是使用虚拟填充的方式。我自己尝试了这段代码,它正在工作。你试过了吗?
  • 我是否应该将我所有其他模式的键包含在像这样{ name: String, email: String, password: String } 这样的对象中?因为在我的问题中查看我的架构
  • @FahadHassanSubzwari 是的,还有关于之前的评论,我只尝试了 toJSON: { virtuals: true },toObject 可能会被删除,但 toJSON 是必需的。
  • 这是说User.virtual is not a function
【解决方案2】:

您说“我在用户中没有 'Referrals' 引用 _id”,所以我假设您在 Referrals 架构中有对用户的引用?

否则,如果没有办法将它们联系起来,恐怕你会迷失在海上...... :-(

如果你这样做了,那么你会在一个单独的查询中这样做:

const userIds = users.map(user => user._id);

const referrals = await Referrals.find({ userId: { $in: userIds } })

$in 运算符将抓取数组中包含用户 ID 的任何字段。

编辑:响应您的更新 - 是的,上面应该可以正常工作。然后你可以对他们做你想做的事,例如将引用映射到用户对象,或单独使用它们等等。

EDIT2:是的,就是这样。此时,您有一组用户和一组推荐,因此您只需将它们放在一起。

users.map(user => ({ 
   // add props from user obj
   ...user, 
   // add all referrals that with matching userId
   referrals: referrals.filter(referral => referral.userId === user._id)
 }))

请记住,当您处理异步调用和 Promise 时,您将需要使用 async/await 关键字,或者在 Promise 回调中解析结果。

【讨论】:

  • 查看我更新的帖子。我不认为使用您的解决方案可以得到想要的结果。
  • 这就是你想要的——你只需要解析结果——我已经更新了
  • “否则,没有办法把它们联系起来,你恐怕会迷失在海上。” => 有一种方法叫做 virtual populate,你可以查看我的答案。
  • @SuleymanSah - 我说如果在推荐中未定义 userId,你就不能这样做。这是正确的 - 您需要该字段才能使用虚拟填充。我坚持我的回答,因为他的架构已经写好了,这显示了幕后发生的事情。
猜你喜欢
  • 2021-08-20
  • 2020-01-23
  • 2021-09-18
  • 2021-02-17
  • 2019-02-19
  • 2016-04-21
  • 2019-07-15
  • 2015-04-18
  • 2022-10-01
相关资源
最近更新 更多