MongoDb aggregate query, how to select field from foreign table? - mongodb

I am running a mongoDb query trying to get the data of my "User" which also include the "CounterParty.name" My aggregate query does get the user back, but does nothing with the fields from Counterparty. I went through the docs several times but cannot seem to figure it out.
My UserSchema
import { Schema, model } from "mongoose";
import mongoose from "mongoose";
export type UserDocument = mongoose.Document & {
email: string;
password: string;
status: string;
name: string;
counterParty: Schema.Types.ObjectId;
}
const userSchema = new Schema<UserDocument>(
{
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
name: {
type: String,
required: true
},
status: {
type: String,
default: "I am new"
},
counterParty: {
type: Schema.Types.ObjectId,
ref: "CounterParty",
}
},
{ timestamps: true }
)
export const User = model<UserDocument>('User', userSchema);
My CounterPartySchema
import { Schema, model } from "mongoose";
import mongoose from "mongoose";
export type CounterPartyDocument = mongoose.Document & {
name: string
}
const counterPartySchema = new Schema<CounterPartyDocument>(
{
name: {
type: String,
required: true,
unique: true,
trim: true
},
},
{ timestamps: true }
)
export const CounterParty = model<CounterPartyDocument>('CounterParty', counterPartySchema);
My query code
const user = await User.aggregate<any>([
{ '$match': { email: email } },
{
'$lookup': {
from: 'CounterParty',
localField: 'counterParty',
foreignField: '_id',
as: 'details'
}
}
])
console.log("user", user)
My console log statement now returns the user, but nothing to see of the counterParty.
Any help will be much appreciates! Cheers

Your aggregation query looks fine in the playground , maybe you dont have such _id: new ObjectId("...786") in the counterParty collection?

Related

How to Find record by ObjectID's property in Mongodb?

Suppose I have 2 models like Orders and Customers.
const orders = mongoose.Schema({
customer_id: {
type: mongoose.Schema.ObjectId
required: true,
ref: 'Customer',
},
OrderNo: {
type: String,
required: true,
})
const customers = mongoose.Schema({
name: {
type: String,
required: true,
})
I want to filter orders based on customer's name as per below.
let query = {
'customer_id.name': { $regex: '.*AMAZON.*' },
}
await Orders.find(query)
but its not working properly. I'm new to mongodb. Can anyone share feasible solution ? Thanks
Try to populate and filter the resulting fields:
await Orders.find({})
.populate({ path: 'customer_id', match: { name: { $regex: '.*AMAZON.*' } } })
.exec();

MissingSchemaError: Schema hasn't been registered for model "Product"

------------------------------
Here is Order Controller
-----------------------------
import nc from "next-connect";
import db from "../../../utils/db";
import Order from "../../../models/OrderModel";
import { isAuth } from "../../../utils/auth";
const handler = nc();
handler.use(isAuth);
handler.get(async (req, res) => {
try {
await db.connect();
const order = await Order.findById(req.body.order).populate({
path: "product",
model: "Product",
});
await db.disconnect();
res.send(order);
} catch (err) {
console.log(err);
}
});
export default handler;
--------------------------------------------------------------
Here is Order Schema
--------------------------------------------------------------
import mongoose from "mongoose";
const orderSchema = new mongoose.Schema(
{
product: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Product",
required: true,
},
],
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
}
},
{ timestamps: true }
);
const Order = mongoose.models.Order || mongoose.model("Order", orderSchema);
export default Order;
----------------------------
Here is Product Schema
----------------------------
import mongoose from "mongoose";
const productSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
category: {
type: String,
required: true,
},
period: {
type: String,
required: true,
},
features: [{ type: String, required: true }],
},
{ timestamps: true }
);
const Product =
mongoose.models.Product || mongoose.model("Product", productSchema);
export default Product;
--------------------
I am getting this error: "MissingSchemaError: Schema hasn't been registered for model "Product".
Use mongoose.model(name, schema)"
There are also some orders including product ObjectId and I am trying to get the data using populate on the POSTMAN but getting this error.
I've really searched much before posting this but I've didn't solve the error

Populate data using another collection in mongoose v6.2.8

Im having issues populating my mongoDB collection with another collection based off the _id. It Keeps returning an empty object with no errors or anything?
Property Schema
const PropertySchema = new Schema({
landlord: {
type: Schema.Types.ObjectId,
ref: "Landlord",
required: true,
},
...
});
Landlord Schema
import { Schema as _Schema, model } from "mongoose";
const Schema = _Schema;
const LandlordSchema = new Schema({
fname: {
type: String,
required: true,
},
lname: {
type: String,
required: true,
},
phone: {
type: Number,
required: true,
},
email: {
type: String,
required: true,
},
company: {
type: String,
},
});
const Landlord = (module.exports = model("Landlord", LandlordSchema));
export function get(callback, limit) {
Landlord.find(callback).limit(limit);
}
Property Controller
exports.readProperty = async (req, res) => {
await Property.find({ _id: req.params.propertyId })
.populate({
path: "Landlord",
select: "fname lname email phone company",
model: "Landlord",
strictPopulate: false,
})
.then(function (err, property) {
if (err) return res.send(err);
res.json(property);
});
};
mongodb Property Collection
Mongodb Landlord Collection
When running the get call from postman it returns:
I fixed this issue by selecting the field: landlord not Landlord

How to use full text search in referenced documents?

I know this was asked before, but I can't find an answer that works for me.
I have some documents, which have reference to another document, like users and orders:
Users model:
import mongoose from '../database/index.js';
import mongoosePaginate from 'mongoose-paginate-v2';
const UsersSchema = new mongoose.Schema({
user_id: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
firstName: {
type: String,
default: '',
},
lastName: {
type: String,
default: '',
},
orders: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Orders',
},
],
recipients: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Recipients',
},
],
createdAt: {
type: Date,
default: Date.now,
required: true,
select: false,
},
});
UsersSchema.index({ email: 'text', firstName: 'text', lastName: 'text' });
UsersSchema.plugin(mongoosePaginate);
UsersSchema.set('toJSON', {
virtuals: true,
});
const Users = mongoose.model('Users', UsersSchema);
export default Users;
Orders model:
import mongoose from '../database/index.js';
import mongoosePaginate from 'mongoose-paginate-v2';
import Users from './users.js';
import OrderStatus from '../enums/OrderStatusEnum.js';
const OrdersSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Users',
required: true,
},
total: {
type: Number,
required: true,
},
status: {
type: String,
enum: OrderStatus.values(),
required: true,
default: OrderStatus.CREATED,
},
payment: {
type: mongoose.Schema.Types.ObjectId,
ref: 'PaymentMethods',
required: true,
},
shortId: {
type: String,
required: true,
},
createdAt: {
type: Date,
default: Date.now,
required: true,
},
});
OrdersSchema.index({ shortId: 'text' });
OrdersSchema.plugin(mongoosePaginate);
OrdersSchema.pre('remove', function (next) {
Users.update({ orders: this._id }, { $pull: { orders: this._id } }).exec();
next();
});
OrdersSchema.set('toJSON', {
virtuals: true,
});
const Orders = mongoose.model('Orders', OrdersSchema);
export default Orders;
I can use the $text search to query full text search from orders or users:
const orders = await Orders.paginate(
{ $text: { $search: query.filter.q } },
query.options
);
return orders;
But this will only make a search on the orders index. If, i.e., I would like to search for the order of the user whose first name is Joe, how can I make it also search in the user.firstName field, since this is a reference from Orders to Users?
I know I can't populate the fields and then search on all model, but I'm not sure how to achieve what I'm looking for.
Thanks in advance
Because full text search query must be the first stage in the aggregation pipeline, it is not currently possible to perform full text search in two collections as part of the same query.
You'll need to reorganize your data.
my requirement was to find orders of users matched with their names, partial or full-text search. the user id is ref into orders doc.
from mongodb playground:
https://mongoplayground.net/p/ASOSFvfURXW
db.inventory.aggregate([
{
"$lookup": {
"from": "orders",
"localField": "orderId",
"foreignField": "_id",
"as": "order_docs"
}
},
{
"$unwind": "$order_docs"
},
{
"$match": {
"order_docs.item": {
"$regex": "pec",
"$options": "i"
}
}
}
])

Complex query mongoose - embedded documents array

I want to execute a query for getting all "group" documents that have the userId in there array of users.
I've tried several different ways of query, but I always get an empty array.
What am I doing wrong?
group.js
let mongoose = require('mongoose');
const Group = mongoose.Schema({
name: {
type: String,
required: true
},
users: [{
userId: {
type: mongoose.SchemaTypes.ObjectId,
ref: 'users',
required: true
},
userType: {
type: String,
required: true
},
userStatus: {
type: String,
required: true
}
}]
})
module.exports = mongoose.model('group', Group);
groupController.js
exports.getUserGroups = function (req, res) {
Group.find({
"users.userid": "req.user._id"
}, function (err, groups) {
if (err)
res.send(err)
res.json(groups);
});
}
Field names are case-sensitive, so "users.userid" should be "users.userId" instead:
Group.find({
"users.userId": "req.user._id"
}, ...
You can try using $in operator
db.collection.find({
"users.userId": {
$in: [
req.user._id
]
}
})