MongoDB Find by id of object inside array - mongodb

I have the following Model-Structure
[{
"orders":
[{
"_id": "5f24839133759d4859ef5233",
"owner": {
"_id": "5f17fdb08145508a94fc1bda"
},
}]
},
...
]
I want to get all objects that have an order with a specific owner id.
I tried find({"orders.owner._id": "5f17fdb08145508a94fc1bda" }) which just returns an empty array.
Tried many other variations also without dot-notation, but nothing worked.
I'm using mongoose to query the MongoDB database.
EDIT:
These are the Mongoose Schemata used for the collection:
const orderPoolShema:mongoose.Schema = new mongoose.Schema({
orders: [{type: mongoose.Types.ObjectId, ref: 'Order' }]
},
{
timestamps: true
});
const orderShema:mongoose.Schema = new mongoose.Schema({
owner: {type: mongoose.Types.ObjectId, ref: 'User', require },
},
{
timestamps: true
});
const userShema:mongoose.Schema = new mongoose.Schema({
firstname: {type: String, required: true},
lastname: {type: String, required: true}
},
{
timestamps: true
});
And this is my Node.js code:
OrderPool.find({"orders.owner._id": mongoose.Types.ObjectId("5f17fdb08145508a94fc1bda") })
.then((orderPools:any) => {
res.send(orderPools);
}).catch((err:any) => {
res.status(500).send({
message: err.message || "Some error occurred while retrieving orderPools."
});
});
Any ideas on how to get that query to work are very appreciated.
Thanks for your help.

Related

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

find one with multiple conditions mongoose mongodb

I am trying to obtain data from mongodb. This is the scenario. Each user has a following property(array) that takes an array of users id.
The user model is as below
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
followers: [{ type: mongoose.Types.ObjectId, ref: "user" }],
following: [{ type: mongoose.Types.ObjectId, ref: "user" }],
});
in simple terms. I need to use two conditions where postedBy: { $in: req.user.following }, or postedBy:req.user._id
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true,
},
body: {
type: String,
required: true,
},
photo: {
type: String,
required: true,
},
likes: [{ type: mongoose.Schema.ObjectId, ref: "user" }],
comments: [
{
text: String,
postedBy: { type: mongoose.Schema.Types.ObjectId, ref: "user" },
},
],
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
},
});
I have not figured out the second condition to add in the code below.
router.get("/getSubPost", requireLogin, async (req, res) => {
try {
const result = await Post.find({
postedBy: { $in: req.user.following },
})
.populate("postedBy", "-password")
.populate("comments.postedBy", "_id name");
res.json({ result });
} catch (error) {
console.log(error);
}
});

retrieving array data in mongodb which match id

Below is the schema. i want to get the answers as per matched qid, but i am getting all the answers in the answers array. i have tried almost all the queries but not able to understand why is this happening, if you could give link to other article that will be helpful too.
const id = req.params.id;
Channel.findOne({answer: {qid: {$in: [id]}}})
.then(result => {
console.log(result);
// let userAnswer;
// userAnswer = result.answer.map(i => {
// return {userId: i.userId , userName: i.userId.name, answer: i.answer}
// });
// res.json({ans: userAnswer, question: result.content});
})
.catch(err => {
console.log(err);
});
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const channelSchema = new Schema({
name: {
type: String,
required: true
},
category: {
type: String,
required: true
},
creator: {
type: String,
required: true
},
subscribers: [{type: mongoose.Types.ObjectId, required: true, ref: 'User'}],
content: {
question: [{
title: {type: String, required: true},
userId: {type: mongoose.Types.ObjectId, required: true, ref: 'User'}
}]
},
answer: [{
answer: {type: String, required: true},
qid: {type: mongoose.Types.ObjectId, required: true},
userId: {type: mongoose.Types.ObjectId, required: true, ref: 'User'}
}]
});
const model = mongoose.model('Channel', channelSchema);
module.exports = model;
const id = req.params.id;
return Channel.findOne({answer: {qid: {$in: [id]}}})
.then(snapshot => {
const results = [];
snapshot.forEach(doc => {
results.push({
id: doc.id,
data: doc.data()
});
});
return results;
})
})
.catch(err => {
console.log(err);
});
This is the way when you are going to fetch one array record. Not tested, only to show you how to get single record from collection

Mongoose populate method on query returns empty array

I am having trouble querying my model, and using the .populate method to grab referenced documents of my object. Here are my schemas:
var userSchema = new Schema({
firstname: { type: String, required: true, unique: false },
lastname: { type: String, required: true, unique: false },
...
children: [{type: mongoose.Schema.Types.ObjectId, ref: 'Child'}],
});
var childSchema = new Schema({
firstname: { type: String, required: true, unique: false },
lastname: { type: String, required: true, unique: false },
...
legal_guardian_id: [{type: mongoose.Schema.Types.ObjectId, ref: 'User'}],
});
And here is how i'm trying to run my query:
User.findOne({ _id: '5b9d30083e33585cc0b8c710' })
.populate('children').exec((err, doc) => {
if (err) { return console.error(err); }
res.send(doc);
})
This results in "children": []
When I just use the findOne method and return the user, I get "children":["5b9d3f23d1408c5f4e2624f3"].
What am I doing wrong?

Mongoose not populating previously saved document with reference to newly saved document

all.
I am writing a MEAN stack application, using Mongoose (4.0.6) with Node/Express to interface with MongoDB, and I am running into difficulty populating saved documents when I later save new documents that the existing document should have a reference to. Specifically, in the app I have a user create an instance of a company before creating their admin account for that company, so when the user registers him/herself as an admin, I'd like the company document to populate its users array with the new user.
Here are my schemas for company and user:
User.js...
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.Types.ObjectId;
var userSchema = new Schema({
first_name: { type: String, required: '{PATH} is required!' },
last_name: { type: String, required: '{PATH} is required!' },
username: { type: String, required: '{PATH} is required!', lowercase: true, unique: true },
password: { type: String, required: '{PATH} is required!' },
roles: { type: [String] },
company: { type: ObjectId, ref: 'Company', required: true },
db_permissions: [{ type: ObjectId, ref: 'DataConnection' }],
created_by: { type: ObjectId, ref: 'User' },
created_at: { type: Date, default: Date.now },
updated_at: [{ type: Date, default: Date.now }]
});
var User = mongoose.model('User', userSchema);
module.exports = {
User: User
};
Company.js...
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.Types.ObjectId;
var companySchema = new Schema({
name: { type: String, uppercase: true, required: '{PATH} is required!', unique: true },
industry: { type: String, required: '{PATH} is required!' },
phone: { type: String, required: '{PATH} is required!' },
address_line_1: { type: String, uppercase: true, required: '{PATH} is required!' },
address_line_2: { type: String, uppercase: true },
city: { type: String, uppercase: true, required: '{PATH} is required!' },
state_prov: { type: String, uppercase: true, required: '{PATH} is required!' },
postal_code: { type: String, required: '{PATH} is required!' },
country: { type: String, required: '{PATH} is required!' },
logo_url: String,
users: [{ type: ObjectId, ref: 'User' }],
data_connections: [{ type: ObjectId, ref: 'DataConnection' }],
created_at: { type: Date, default: Date.now },
updated_at: [{ type: Date, default: Date.now }]
});
var Company = mongoose.model('Company', companySchema);
module.exports = {
Company: Company
};
Here is the code in my controller:
User.create(userData, function(err, user) {
if(err) {
if(err.toString().indexOf('E11000') > -1) {
err = new Error('Duplicate email');
}
res.status(400);
return res.send({ reason:err.toString() });
}
console.log('company id: ' + user.company);
Company.findById(user.company)
.populate({path: 'users'})
.exec(function (err, company) {
if (err) return handleError(err);
console.log(company.name + '\'s users now includes ' + company.users);
});
res.send(user);
The company (e.g. TEST53) saves to the database correctly with an empty users array:
{
"_id": "55ae421bf469f1b97bb52d5a",
"name": "TEST53",
"industry": "Construction",
"phone": "2352626254",
"city": "GDFGD",
"country": "United States",
"address_line_1": "DSGDFGH",
"state_prov": "GF",
"postal_code": "45645",
"logo_url": "",
"__v": 0,
"updated_at": [
"2015-07-21T12:59:07.609Z"
],
"created_at": "2015-07-21T12:59:07.597Z",
"data_connections": [],
"users": []
}
Then when I create the user, it saves correctly:
{
"_id": "55ae4238f469f1b97bb52d5b",
"username": "test53#test.com",
"password": "$2a$12$ZB6L1NCZEhLfjs99yUUNNOQEknyQmX6nP2BxBvo1uZGlvk9LlKGFu",
"company": "55ae421bf469f1b97bb52d5a",
"first_name": "Test53",
"last_name": "Admin",
"__v": 0,
"updated_at": [
"2015-07-21T12:59:36.925Z"
],
"created_at": "2015-07-21T12:59:36.550Z",
"db_permissions": [],
"roles": [
"admin"
]
}
And I can see that the correct ObjectId prints to the console for user.company:
company id: 55ae421bf469f1b97bb52d5a
But the company's users array doesn't populate with the user's id, and the console.log inside the .exec function prints 'TEST53's users now includes '.
I have tried several ways of wiring this up, with just 'users' instead of { path: 'users' }, writing a function that pushes the user into the array, using .run instead of .exec, but so far without success.
Is there something obvious I'm missing? Thanks in advance for any suggestions!
You're not actually adding the user to the company.
Try this:
Company.findById(user.company, function (err, company) {
if (err) return handleError(err);
// Add the user to the company's list of users.
company.users.push(user);
// Need to save again.
company.save(function(err) {
if (err) return handleError(err);
console.log(company.name + '\'s users now includes ' + company.users);
});
});
res.send(user);
It seems to me that all you want to do is to update the Company model to add the user, as opposed to actually use the (populated) Company document as a response, so I left out an additional Company.findById(...).populate(...) call.