我如何使用猫鼬在循环中迭代猫鼬返回的文档数组?

时间:2019-11-21 11:49:45

标签: javascript node.js mongodb express mongoose

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

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

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

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。但是很遗憾,我在_id文档中没有“ Referrals”参考Users。现在,我想让所有用户拥有各自的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 ... 
                    }
                ]
            },
        ]

2 个答案:

答案 0 :(得分: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);

答案 1 :(得分:0)

您说“我在用户中没有'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)
 }))

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