Javascript 如何在MongoDB中按引用字段查询?

Javascript 如何在MongoDB中按引用字段查询?,javascript,node.js,mongodb,mongoose,aggregation-framework,Javascript,Node.js,Mongodb,Mongoose,Aggregation Framework,我有两个Mongo模式: 用户: 国家: { _id: ObjectId, name: String } 我想获得所有国家名为“越南”的用户 对于这种情况,我可以使用哪种查询(仅针对用户架构) 我希望它看起来像以下SQL查询: SELECT * FROM User JOIN Country ON User.country = Country._id WHERE Country.name = 'VietNam' 与关系数据库不同,这不是Mongo擅长的,当您使用NoSQL时,通常

我有两个Mongo模式:

用户:

国家:

{
  _id: ObjectId,
  name: String
}
我想获得所有国家名为“越南”的用户

对于这种情况,我可以使用哪种查询(仅针对用户架构)

我希望它看起来像以下SQL查询:

SELECT * 
FROM User
JOIN Country 
ON User.country = Country._id 
WHERE Country.name = 'VietNam'

与关系数据库不同,这不是Mongo擅长的,当您使用NoSQL时,通常应该以不同的方式构造模式。在这种情况下,您可以将
countryName
字段添加到
user
集合中(可能还有国家索引),以便查询
{countryName:“越南”}
。(使用iso-2国家代码可能比使用国家名称更有意义)


如果您确实需要进行“连接”,您可以使用--请记住,聚合的伸缩性不好,而且往往有点难以编写。

以下是我通常使用的代码:

Models/users.js


const mongoose = require("mongoose");
const Countries = require("./countries");

const UsersSchema = new mongoose.Schema({
    name: Sting,
    country: Countries.schema
});

module.exports = mongoose.model("Users", UsersSchema);
const express = require("express");
const router = express.Router();
const Users = require("../models/users");

router.post("/register", async(req, res) => {
    try{
      const Me = await Users.create({name: req.body.name, country: req.body.country})
      /* If you make the request correctly on the frontend req.body.name is a 
         string and req.body.country is an object with one property, it's name */
      res.status(200).json({
          data: Me
      });
    }
    catch(err){
      res.status(400).json({message:err.message})


controllers/users.js


const mongoose = require("mongoose");
const Countries = require("./countries");

const UsersSchema = new mongoose.Schema({
    name: Sting,
    country: Countries.schema
});

module.exports = mongoose.model("Users", UsersSchema);
const express = require("express");
const router = express.Router();
const Users = require("../models/users");

router.post("/register", async(req, res) => {
    try{
      const Me = await Users.create({name: req.body.name, country: req.body.country})
      /* If you make the request correctly on the frontend req.body.name is a 
         string and req.body.country is an object with one property, it's name */
      res.status(200).json({
          data: Me
      });
    }
    catch(err){
      res.status(400).json({message:err.message})



因为子模式是一个对象,所以将其引用为Me.country.name。希望这有帮助

您可以将下面的聚合与mongodb3.6及以上版本一起使用

db.country.aggregate([
  { "$match": { "name": "VietNam" } },
  { "$lookup": {
    "from": Users.collection.name,
    "let": { "countryId": "$_id" },
    "pipeline": [
      { "$match": { "$expr": { "$eq": [ "$country", "$$countryId" ] } } },
    ],
    "as": "users",
  }},
  { "$unwind": "$users" },
  { "$replaceRoot": { "newRoot": "$users" }}
])

如果要关联2个或多个集合,则必须定义集合的引用对象


我的解决方案请检查此

以便在我更新countryId A的国家名称时。我必须找到所有具有countryId A的用户记录,并更新所有记录??性能没问题国家名称(或iso-2国家代码)更改的频率是多少?更新所有用户实体是一项非常昂贵的操作,但这种操作很少发生(并且可以通过让应用程序端代码进行重命名来避免)。对每个查询进行额外的查找最终会花费更高的成本。但是对于通常需要更改的记录,您通常需要在mongo中对数据进行非规范化处理&这项工作的一部分通常涉及确保多个文档保持同步。如果记录经常更改,使用$lookup可以让您返回来自不同集合的文档。如何构造数据和查询在很大程度上取决于您的用例。但我想保留2个模式,用户只存储国家Id,而不是国家对象。由于国家/地区集合将用于显示列表国家/地区,因此应将其分隔为2个模式。主要的问题是,我不知道如何按国家/地区名称向用户查询,您仍然有2个文档集合,但如果您想按国家/地区调用用户,则需要
Users.findMany({country:req.body.country})
。我猜我看错了你的问题,但这是一个很好的参考MongoDB的所有东西。效果很好。但是我可以将user.name='Anthony'和country.name='Vietname'这两个条件组合起来吗?