I have a system with mongodb genericized by mongoose in nest js how do I bring customer and product data in the same request
in the database the data is like this:
"_id": "621d2137abb45e60cf33a2d4",
"product_id": [
"621cedbf79d68fb4689ef0cb",
"621cedbf79d68fb4689ef0cb",
"621cedbf79d68fb4689ef0cb"
],
"client_id": "621d19f890ec693f1d553eff",
"price": 597,
"__v": 0
my serviçe:
findAll() {
return this.sealsModel.find().exec();
}
This way didn't work:
findAll() {
var a = this.sealsModel.find().exec()
return this.sealsModel.aggregate([{
$lookup: {
from: 'seals',
localField: 'client_id',
foreignField: '_id',
as: 'client'
}
}])
.exec()
}
but return this:
"_id": "621d3e0a1c3bcac85f79f7cc",
"product_id": [
"621cedbf79d68fb4689ef0cb",
"621cedbf79d68fb4689ef0cb",
"621cedbf79d68fb4689ef0cb"
],
"client_id": "621d19f890ec693f1d553eff",
"price": 597,
"__v": 0,
"client": []
An alternative to Mongo's $lookup operator is Mongoose's populate function. In order to use it properly, you first have to update your model.
You should have a client model that looks like this:
// /models/Client.js
const mongoose = require("mongoose");
const clientSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
... // the rest of your fields
});
module.exports = mongoose.model('Client', clientSchema);
The key thing to notice here is the last line. The model is referenced as "Client".
The change you have to make is mainly in your Seal model :
// /models/Seal.js
const mongoose = require("mongoose");
const sealSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
client_id: {
type: mongoose.Schema.Types.ObjectId,
ref: "Client" // We use the same name we gave to our client model in the last file
}
});
module.exports = mongoose.model('Seal', sealSchema);
Then, in your code, you should be able to use:
const Seal = require("YOUR_PATH/models/Seal.js")
Seal.find().populate("client_id")
One important side note: your model shows the mongo ID as a string
"_id": "621d3e0a1c3bcac85f79f7cc",
"client_id": "621d19f890ec693f1d553eff", <---
Make sure that the field client_id is of type ObjectId or it won't work:
"client_id": ObjectId("621d19f890ec693f1d553eff")
Related
I have two schemas defined, imageSchema and userSchema. imageSchema has key postedBy: userSchema. Question is shall I remove unused attributes of userSchema (like password) when nested into imageSchema, if so how to do it?
var userSchema = new mongoose.Schema({
email: String,
password: String,
name: String,
}, {versionKey: false})
var imageSchema = new mongoose.Schema({
filePath: String,
user: userSchema,
createdAt: Date,
comments: [{body: "String", by: mongoose.Schema.Types.ObjectId}]
})
...
app.post("/upload-image", async function(req, res){
if(req.session.user_id) {
...
fileSystem.rename(oldPath, newPath, function(err2){
getUser(req.session.user_id, function(user){
delete user.password
var currentTime = new Date().getTime()
Image.create({
"filePath": newPath,
"user": user,
"createdAt": currentTime,
"comments": []
}, function(err2, data){
res.redirect("/?message=image_uploaded")
})
...
So after I created a new document of Image, I checked the database, the user field of the new Image has the attribute of password, which is not desired. "delete user.password" seems not working. How should I delete this attribute? Shall I do it when defining the imageSchema, or remove it when posting the data (the app.post part)?
This can be done is multiple ways. The way i like is to exclude the field from schema and also exclude while insertion.
Exclude from schema
var imageSchema = new mongoose.Schema({
filePath: String,
user: userSchema.pick(["email", "name"]), // this will return schema with only email and name from the schema
createdAt: Date,
comments: [{body: "String", by: mongoose.Schema.Types.ObjectId}]
})
Exclude while inserting
we are omitting the user here before insertion
this can be also done with underscore/lodash _.omit(user, 'password')
getUser(req.session.user_id, function({password, ...user}){
Image.create({
"filePath": newPath,
"user": user,
"createdAt": Date.now(),
"comments": []
})
}
I have MongoDb as my db . data in this instance is populated on a daily basis through a csv file import.
a document in this collection/csv looks as
{
"_id": {
"$oid": "611e455ddd7c222661065037"
},
"country": "India",
"country_code": 91,
"country_iso": "IND",
"origination_prefix": "",
"voice_rate_in_usd": 0.3148,
"voice_unit_in_seconds": 60
}
This data is fetched via node.js api as below
//some code emitted for brevity
import { connect, Schema, model } from "mongoose";
import express from "express";
const router = express.Router();
const schema = new Schema<Pricing>({
country: { type: String, required: true },
countryCode: { type: String, required: false },
countryIso: { type: String, required: true },
destinationPrefix: { type: [Number] },
voiceRate: { type: Number },
voiceUnit: { type: Number },
});
const pricesModel = model<Pricing>("call_rate", schema);
router.get("", async (req, res) => {
const prices = await pricesModel.find().limit(10);
res.send(prices);
});
export default router;
Being a newbie to node.js on googling I get a number of packages
https://www.npmjs.com/package/typescript-json-object-mapper
https://www.npmjs.com/package/object-mapper
https://www.npmjs.com/package/serialize-ts
now I am not sure which is the most common/popular/recommended package & how do I use it
How can I map my DB object to the app object?
Thanks!
Since you are using MongoDB and Mongoose, you don't have to do anything. Mongoose will automatically return objects or array of objects for each query.
I have created two model users and post where users reference post.
This is my user model.
var mongoose = require("mongoose");
mongoose.connect("mongodb://localhost:27017/demo",{ useNewUrlParser: true });
var Post = require('./post');
var UserSchema = mongoose.Schema({
username: String,
password: String,
posts:[{
type:mongoose.Schema.Types.ObjectId,
ref: Post
}] });
This is my post model
var postSchema = mongoose.Schema({
title:String,
content: String,
likes:Number
});
When I create and save a new post to a specific user I get an id in the post field of the user model. like this:-
{
posts: [
60e33a2d18afb82f8000d8f0,
],
_id: 60d9e931b5268920245c27f0,
username: 'user1',
password: '1234',
__v: 5
}
How do I access and display the contents of the post field?
Thanks!
You can get and display Reference data in MongoDB with Aggregate.
Like:
await User.aggregate([
{
$match: { _id: ObjectId(user._id)}
},
{
$lookup: { from: "Posts", localField: "post", foreignField: "_id", as: "posts" }
},
{
$unwind: { path: "$users", preserveNullAndEmptyArrays: true,}
}, {
$project: {
" Now you can select here whatever data you want to show "
}
}
])
PS: If you have any confusion please do comment.
Thanks
Mongoose has a powerful alternative to using aggregate. You can do this with populate .
Use it like this 👇 this will populate the ids inside the posts field with the actual post documents.
User.findById(id).populate('posts')
// Full example
try {
const user = await User.findById(id).populate('posts').exec();
for (let post of user.posts) {
console.log(post.content);
}
} catch (ex) {
console.error(ex);
}
If I may, a small suggestion on how to setup your document model or just to show you an alternative. Don't reference the Posts inside your User Document. Do it the other way round and reference the User inside your Post Document.
const postSchema = mongoose.Schema({
title : String,
content : String,
likes : Number,
user : { type:mongoose.Schema.Types.ObjectId, ref: 'User' }
});
// GET ALL POSTS FROM ONE USER
Post.find({user:id});
This way you don't need to use populate when trying to show all posts of 1 user.
I have a firebase project that I use for authentication. I also save additional user info in the mongodb and assign the uid of the firebase user to the _id field of the user model. In order to do that, I have to set the type of ObjectId to a String, otherwise mongodb doesn't let me save the user as the firebase uid is a bit longer than ObjectId. It seems that the ObjectId is of type:String, I can no longer use populate on my queries.
Here are the models:
const UserSchema = new Schema({
_id: String,
name: String,
});
const SurveySchema = new Schema({
user_id: { type: String, ref: "users" },
category: String,
});
I tried to set user_id: { type: mongoose.ObjectId, ref: "users" }, but I just get an error(Cast to ObjectId failed) instead of undefined.
Here is the controller where I use populate:
const SurveyList = await Survey.find(
{
user_id: req.currentUser.uid,
category: "example",
},
"_id user_id category createdAt updatedAt"
).populate("user_id");
I checked, the ids match, but I still get undefined. The populate used to work when I had regular mongo ObjectIds, but after I started using firebase it no longer works.
The response I get is like this:
"SurveyList": [
{
"status": "1",
"_id": "60abcd94e9cddb2ba44f24b4",
"user_id": null,
"category": "Health",
"createdAt": "2021-05-24T16:00:20.688Z",
"updatedAt": "2021-05-24T16:00:20.688Z"
}
]
Please note that the error began occurring only after I changed _id to type:String. It used to work fine when it was a default mongoose.ObjectId
You cannot populate the field that you're using to store the reference to the user's id. That field is the one that will be used in order to populate the virtual field. If what you want to do is having a virtual field SurveyList[i].user that retrieves the user's data in each SurveyList entry, you need to create it:
SurveySchema.virtual("user", {
ref: "users",
localField: "user_id",
foreignField: "_id",
justOne: true,
});
Then you'll need to populate the virtual field:
const SurveyList = await Survey.find(
{
user_id: req.currentUser.uid,
category: "example",
},
"_id user_id user category createdAt updatedAt"
).populate("user");
I have the next Schema:
'use strict';
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = Schema({
id: String,
name: [{
name: String,
surname1: String,
surname2: String,
}]
});
module.exports = mongoose.model('User', userSchema);
And I created the next function:
module.exports.signUp = function(req,res){
console.log('POST signUp');
let user = new User();
for(var key in req.body) {
console.log(key);
switch (key) {
case 'name[name]':
user.name.push({name:"name"});
break;
case 'name[surname1]':
user.name.push({surname1:"surname1"});
break;
case 'name[surname2]':
user.name.push({surname2:"surname2"});
break;
}
}
res.status(202).send({message: user});
}
I need the next results:
{
"message": {
"_id": "5b61e242c4874a045dd4185a",
"name": [
{
"name": "name",
"surname1": "surname1",
"surname2": "surname2"
}
]
}
}
And I get:
{
"message": {
"_id": "5b61e242c4874a045dd4185a",
"name": [
{
"_id": "5b61e242c4874a045dd4185b",
"name": "name"
},
{
"_id": "5b61e242c4874a045dd4185c",
"surname1": "surname1"
},
{
"_id": "5b61e242c4874a045dd4185d",
"surname2": "surname2"
}
]
}
}
It generates multiples _id and different JSON format.
I tried with user.name[0]="name", user.name.name="name" but It doesn't work...
When I tried user.name = {"name":"name"} works, but after that I put
user.name = {"surname1":"surname1"} and the name doesn't exists.
Can you help me please?
Thank you!
You're looping through req.body and pushing a key each time. You need to be doing it all at once. Something like
const name={};
if ('name[name]' in req.body){name.name=req.body['name[name]'];}
if ('name[surname1]' in req.body){name.surname1=req.body['name[surname1]'];}
if ('name[surname2]' in req.body){name.surname2=req.body['name[surname2]'];}
user.name.push(name);
Each entry in the name array will have a separate id though because they're declared as a subdocument in Mongo. You'll still be able to access the user by its id, but you'll also have access to each name object individually.
If each user just needs one name though, you can simplify the schema to
const userSchema = Schema({
id: String,
name: {
name: String,
surname1: String,
surname2: String,
}
});
and then when you have made the name object do
user.name=name;