Impossible to query nested mongoose array? - javascript

I want to Query and array with regex inside and mongoose (mongoDB) model.
I want to search inside the nested array of the Productmodel :
const productSchema = new schema(
{
name: requiredString,
sku: requiredUniqueNumber,
ean: requiredUniqueNumber,
suppliers: [{ type: mongoose.Schema.Types.ObjectId, ref: SupplierModel }],
categories: [{ type: mongoose.Schema.Types.ObjectId, ref: CategoryModel }],
mainImage: requiredString,
images: [{ type: String }],
description: requiredString,
stock: requiredNumber,
price: requiredNumber,
totalOrders: requiredNumber,
reviews: [review],
},
{
timestamps: true,
count: true,
}
);
The model inside the "suppliers" array is:
const supplierSchema = new schema(
{
supplierName: requiredUniqueString,
invoiceAddress: address,
visitAddress: address,
status: supplierStatusEnum,
contacts: address,
accountType: accountTypeEnum,
logo: requiredString,
user: { type: schema.Types.ObjectId, ref: "products" },
},
{
timestamps: true,
}
);
Now here's the problem, if i query and and populate() i get all the results. But for some reason I cannot search inside the Array containing several suppliers. Here's of what i have:
foundProducts = await ProductModel.find({
$or: [
{
name: {
$regex: regex,
},
},
{
"suppliers.supplierName": {
$regex: regex,
},
},
{
description: {
$regex: regex,
},
},
],
});
The object in JSON:
If he finds that the suppliers model contains the regex he should give back the whole porductmodel containing that supplier.
What is the best way to search in all the items inside of an nested array.
ps. I'm a junior developer comming from PostgreSQL, so bare with me while I'm trying this noSQL "thing" :)

I was doing the wrong query. I need to do
{
"suppliers._id": {
$regex: regex,
},
},
I can only search on _id, since this is the way that i "modeled" it.

Related

What is the best way to send both Image and JSON to my express server?

Ok, so I got a mongodb database, and I am using mongoose.
I have the following model for my product.
const productSchema = new Schema({
name: { type: String, required: true},
description: { type: String, required: true },
price: { type: Number, required: true },
image: { type: String, required: true },
usage: { type: String, required: true },
species: [{
specie: { type: String, required: true }
}],
ingredients: [{
name: { type: String, required: true },
quantity: { type: String, required: true },
}],
});
What I am trying to do is send both an image and JSON in a SINGULAR http request. I found out that this is not really possible. So what is the best to achieve this?
Send two different HTTP requests, one with the json/text data, and one with the file? This would mean that I need to edit my model and make the fields unrequired, and it would be a bit rough to debug in case something goes wrong with one of the requests.
const newProduct = {
name: name,
description: description,
price: price,
usage: usage,
ingredients: itemList,
species: speciesList,
image: image,
};
const [itemList, setItemList] = useState([
{ name: "", quantity: "" },
]);
const [speciesList, setSpeciesList] = useState([
{ specie: "" },
]);
This is what I am trying to send
It's simple. you can send the data to the express server with multipart/form-data structure and then in the server should parse received data and map the values as defined model and finally store into mongo db.

Mongoose - Populating a nested array of objects not working

I have a collection called Orders that contains this schema:
const mongoose = require('mongoose');
const orderSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
},
restaurant: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Restaurant',
required: true
},
dishes: [
{
dish: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Dish'
},
amount: Number
}
],
price: {
type: Number,
required: true
},
comment: {
type: String,
required: false
},
status: {
type: String,
enum: ['PROCESSING', 'CANCELLED', 'COMPLETED', 'ERROR'],
default: 'PROCESSING'
},
timestamp: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Order', orderSchema);
Inside my router, I have this code:
let orders = await Order.find({restaurant: restaurantID, status:'PROCESSING'}).populate('dishes._id').exec()
Order.find does not throw an exception, but it isnt working either.
I want the res.body to look like this:
{
"_id": "objectID",
"user": "objectID",
"restaurant": "objectID",
"dishes": [
{
"amount": number,
"dish": {
//dish object
}
},
...
],
//other order properties
},
...
]
But for some reason the dishes array looks like this:
"dishes": [
{
"amount": 1,
"_id": "6184e848e6d1974a0569783d"
}
],
What am I doing wrong?
I know that if populate() worked the res.body dishes array would not have a property called 'dish' and instead have a property called _id that would contain the dish object, but this shouldnt be hard to change once populate() works.
EDIT:
I realised that my createOrder route could be part of the problem since it ignores my schema and uses an id property for the objectID instead of dish. The array I save to the DB contains a property called id for the id instead of dish, but shouldnt my schema throw an exception when i try to save something like this to my database?
At first glance, I think the problem might be that you have a syntax problem.
Try
.populate('dishes').exec()
instead of
.populate('dishes._id').exec()

how to save data to the array in mongoose

I am building an application where user's can save many images along with its name. I want that information to be stored in mongoose in an array. How to do this?
Here is my mealSchema,
const MealSchema = new mongoose.Schema({
userId: {
type: String,
required: true,
},
meals: [
{
mealImg: {
type: String,
},
mealName: {
type: String,
},
},
],
});
how to save data to this schema.
I want the result to be like this :
{ _id: 5fd662b596ac96247463fab8,
userId:"someid"
meals: [
{
_id:23242fff,
mealName:"meal1",
mealImg:"https://meal1.png"
},
_id:23242fff,
mealName:"meal2",
mealImg:"https://meal3.png"
},
_id:23242fff,
mealName:"meal3",
mealImg:"https://meal4.png"
},
] }
You can write smth like this:
Meal.insert({ userId: someId, meals: arrayOfMeals })
But this is not a good practice, because you can put unnecessary and incorrect information in the array. Such problems are solved by intermediate tables and links between them. I advise you to create another table, the scheme of which will be as follows:
const UsersMealsSchema = new mongoose.Schema({
userId: {type: mongoose.Schema.Types.ObjectId, ref: 'User'},
mealId: {type: mongoose.Schema.Types.ObjectId, ref: 'Meal'},
});
Then change your Meals shema:
const MealSchema = new mongoose.Schema({
id: {
type: string,
required: true,
}
mealImg: {
type: String,
required: true,
},
mealName: {
type: String,
required: true,
},
});

Mongoose populate referencing object id, not the object itself

Background
Here's part of my User model:
const Group = require("./Group")
...
groups: {
type: [{ type: Schema.ObjectId, ref: Group }],
default: [],
},
And here's my Group model:
module.exports = mongoose.model(
"Group",
new Schema(
{
name: {
type: String,
required: true,
unique: true,
},
/**
* Array of User ObjectIDs that have owner rights on this group
*/
owners: {
type: [{ type: Schema.ObjectId, ref: User }],
default: [],
},
},
{
timestamps: true,
}
)
)
The Code
Here's the code I'm running to try and populate:
const user = await (await User.findOne({ _id: ... })).execPopulate("Group")
console.log(user.groups)
My console.log is outputting an array of object IDs, when I'd like it to output an actual Group document.
Attempted solutions
I've tried changing my ref to be using the string ("Group"), I've tried arranging my query differently, etc. I'm not sure how I'd go about doing this.
Apologies in advance if this is a duplicate, I've done my best to search but can't really find a solution that works for me.
Specifically, what do I need help with?
I'm trying to create a 'link' between a user model and a group model. In my console.log, I expect it to output a Group document; but it outputs an object ID (which is how it's stored raw in the database, meaning that Mongoose isn't transforming it correctly)
When you change execPopulate to populate like:
async function findUserAndPopulate(userId){
const response = await User.findOne({
_id: userId,
}).populate('groups')
console.log("response",response)
}
You got:
{
groups: [
{
owners: [Array],
_id: 5ecc637916a2223f15581ec7,
name: 'Crazy',
createdAt: 2020-05-26T00:31:53.379Z,
updatedAt: 2020-05-26T00:31:53.379Z,
__v: 0
}
],
_id: 5ecc6206820d583b99b6b595,
fullname: 'James R',
createdAt: 2020-05-26T00:25:42.948Z,
updatedAt: 2020-05-26T00:36:12.186Z,
__v: 1
}
So you can access the user.groups
See the doc: https://mongoosejs.com/docs/populate.html

Upsert: Unable to invalidate a subdocument that has not been added to an array

I have an upsert query in mongoose which was working in 3.8 but, after I've upgraded to 4 I'm getting
Unable to invalidate a subdocument that has not been added to an array
this is my model:
var ActivitySchema = new Schema({
owner:{
type: Schema.Types.ObjectId,
ref: 'User'
},
sequence:{
type:Number,
default: 0
},
items:[
{
posted:{
type:Date,
default:Date.now
},
verb:{
type: String,
enum: [ 'leave','join','support','share','comment', 'upload', 'rate','message','update', 'signup']
},
text:{
type: String,
},
reference: {
objectType:{
type: String,
enum: [ 'document','element','process', 'project', 'user']
},
refObj:{}
}
}]
});
the upsert:
Activity.update({
$and:[
{'owner':ownerId},
{'sequence':bucket}
]},
{
$push:{items:newItem }
},
{
upsert:true
}).execAsync();
and the data is like this:
//newItem
{ verb: 'join',
text: 'Has joined to a team',
reference:
{
refObj: { teamId: '56269fd1e923cc7a7b46dcf8', name: 'test1' },
objectType: 'user'
}
}
ownerId is a mongoId like 56251c01507dc35423694118
and bucket is an integer 0
is there any breacking change that I need to be aware?, I've been looking and I haven't found yet related, any other workaround, solution?
I had encountered the same problem, if it is the same case then make sure all fields type are matched to the mongoose.model('yourModel').
Hopes that helps.

Categories