4

I have two Mongo schemas:

User:

{
  _id: ObjectId,
  name: String,
  country: ObjectId // Reference to schema Country
}

Country:

{
  _id: ObjectId,
  name: String
}

I want to get all users who have the country name "VietNam".

What kind of query (only to the User schema) can I use for this case?

I want it to look like this SQL query:

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

4 Answers 4

6

You can use below aggregation with mongodb 3.6 and above

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" }}
])
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. It's worked very well. But can I combine conditions as user.name = 'Anthony' and country.name = 'VietNam' ?
you can. pipeline can contain multiple condition.
2

Unlike relational databases, this isn't something that Mongo is good at, and you should generally structure your schemas in a different way when you're using NoSQL. In this case, you could add a countryName field to the user collection (and perhaps an index on country) so that you can query {countryName: "Vietnam"}. (Instead of country-name, it'd likely make more sense to use the iso-2 country code)

If you do need to do a "join" you can use the $lookup operator in the aggregation pipeline -- just keep in mind that aggregations don't scale well and tend to be a little hard to write.

4 Comments

So when I update country name of countryId A. I have to find all User records have countryId are A and update all that records ?? It's ok for performance
How often do country names (or iso-2 country codes) change? Updating all user entities is a really expensive operation, but it's one that will only happen rarely (and can be avoided by having application-side code do the rename). Having an extra look-up with every query is going to end up being much more expensive.
But with records usually to be changed ?
In general, you'll want to denormalize your data in mongo & part of that work often involves making sure that multiple documents stay in sync. If records often change, using $lookup can let you return documents from different collections. How to structure your data & queries depends strongly on your use-case
1

if you want to associate 2 or more collections you must define the reference object of the collection

my solution please check this https://mongoosejs.com/docs/populate.html

Comments

-1

Heres the code I generally use:

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);

controllers/users.js

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})


Since the subschema is an object you reference it as Me.country.name. Hope this helps!

2 Comments

Thanks. But I want to keep 2 schema and User only store country Id, not country Object. Because country collection will be used to show list countries, should separate to 2 schema. And main problem is I don't know how to query to user by country name
you would still have 2 collections of documents but if you want to call the user by the country you do Users.findMany({ country: req.body.country}). I guess I read your question wrong but this is a great reference to all things MongoDB.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.