I have a one-to-many relationship where a place can have multiple reviews. Here are the 2 schemas
export const PlaceSchema = new mongoose.Schema({
name: { type: String, required: true, unique: true },
center: { type: [Number], required: true },
borders: { type: [], required: true },
reviews: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Review' }]
});
export const ReviewSchema = new mongoose.Schema({
user: { type: String, required: true },
city: { type: mongoose.Schema.Types.ObjectId, ref: 'Place', required: true },
creation_date: { type: Date, required: true },
...
});
I have reviews with correct place ID. But when I do a simple this.placeModel.find().populate('reviews').exec(), the reviews always come back as an empty array. But the IDs seem to be fine, as visible here (place on the left, review on the right)
It's my first side project where I play with with Mongo, so I don't really see what I'm missing.
Your query this.placeModel.find().populate('reviews').exec() will work in this manner:
Find all place documents from the places collection.
For each place document, iterate through the reviews field (of array type) and search for the document in the reviews collection with the matching id, and replace the array element with the review document.
Return the list of place documents where the reviews field has been populated with the review documents.
Hence, you need to ensure that your place documents contain the correct id of the review documents in the reviews field instead of ensuring that you have the correct place id in the review documents for the query you want to execute.
Related
I am working on e-commerce like app. I have orderItem Schema
const orderItemsSchema = mongoose.Schema(
{
order: {
type: mongoose.Schema.Types.ObjectId,
ref: 'OrderItems',
required: true,
},
product: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Products',
required: true,
},
quantity: {
type: Number,
default: 1,
},
subCost: {
type: Number,
required: true,
},
},
{
timestamps: true,
}
);
Where product schema has a field "owner" which is also a reference.
I am expecting to get orderItems based on owners of the products.
For Example: A owner want to check which products of him has been sold. So he will query orderItems to get his sold items.
I'm not an expert in mongoose, so maybe the syntax is not entirely correct:
// You get all products _id that owner currently sells
const yourOwnerObjectId = mongoose.Types.ObjectId(yourOwnerId); // Create the objectId from a string
const productsOwner = Products.find({owner: yourOwnerObjectId}).select({_id: 1})
// You get all orders that contains any of previous product _id
const orderWithProductsSold = OrderItems.find({_id: {$in: productsOwner}})
I'm not sure about what returns the first query regarding _id. Maybe you have to do some type of casting to ObjectId or whatever to perform the second query, but I think the idea is right.
I created a simple dynamic fields in React-Redux with a plus button to add as many field as I want (hobbies) of an already existing form. I'm using mongodb as a database and so I have this error that tells me that my fields/data don't have iDs.
so how can I generate iDs for my data?
this below is my model with featherJs. as you can see this is how I added my hobbies array in the existing model called myService. I can see that my hobbies are created in mongo (using Robo 3T) which is great but i'm having difficulty reusing them (hobbies) in an other component in Redux. I'm not sure if I should give IDs to this fields or create a new service just for them. I never coded something in backend so I'm confused. what's the rule for this kind of situations.
Any other suggestions would be helpful.
warning in Redux: Each child in a list should have a unique "key" prop.
error in api : Cast to ObjectId failed for value at path "_id" for model "
const { Schema } = mongooseClient;
const myService = new Schema({
type: { type: String, enum: VALID_TYPES, required: true },
user: {
type: mongooseClient.Schema.Types.ObjectId,
ref: 'user',
required: true
},
comment: String,
hobbies: [{
type: mongooseClient.Schema.Types.ObjectId,
ref: 'hobbies',
default: [],
required: false }],
date: {
begin: { type: Date, default: Date.now },
current: { type: Date, default: Date.now },
end: { type: Date, required: true },
},
}, {
timestamps: true
});
return mongooseClient.model('myService', myService);
};
I have searched for join two collection in MongoDB. I found populate. But it is not working for my scenario. I am using mongoose in node js. My schema are like below.
const CoordinateSchema = new mongoose.Schema({
activationId: {
type: mongoose.Schema.ObjectId,
ref: 'Activation'
},
mac: {
type: mongoose.SchemaTypes.String,
required: true,
set: toLower
},
t: { type: Date },
userId: {
type: mongoose.Schema.ObjectId,
ref: 'User'
}
});
const UserSchema = new mongoose.Schema({
email: {
type: mongoose.SchemaTypes.String,
required: true,
//unique: true,
set: toLower
},
mac: {
type: mongoose.SchemaTypes.String,
required: true,
unique: true,
set: toLower,
index: true
},
dob: {
type: mongoose.SchemaTypes.Date,
},
gender: { type: mongoose.SchemaTypes.String, set: toLower },
activations: [{
activationId: {
type: mongoose.Schema.ObjectId,
ref: 'Activation'
},
userType: { type: mongoose.SchemaTypes.String, set: toLower },
_id: false
}]
}
i have thousands of records for single activation in coordinates collection.
My query query requires to filter distinct mac from coordinates collection which matches userType in user collection.
If i use populate method & then apply filter on that it won't restrict fetching record count because of it query is taking so much time because it will return thousands of records.
I want to fetch only coordinates which match userType in user collection.
So far i haven't found any efficient method to join two collection & apply where condition on it.
I want to know efficient method to join two collection in mongodb & apply where condition on both collections.
I'm wondering what the "Mongo Way" is for modeling a pending trade of an item between two users.
I have a user collection and I have a book collection. In my app, the users will be able to propose trades to one another. Until the trade proposal is accepted, the trade needs to be stored as a pending trade in the database.
It seems to me that the best option is to have a 'trades' property on each book document modeled like this (using Mongoose):
const booksSchema = new Schema({
title: { type: String, required: true },
createdAt: { type: Date, 'default': Date.now },
updatedAt: { type: Date, 'default': Date.now },
author: { type: String, required: false},
imageUrl: { type: String, required: false},
ownerUser: { type: Schema.ObjectId, required: true },
trades: [{
fromUser: { type: Schema.ObjectId, required: true },
bookOffered: { type: Schema.ObjectId, required: true }
}]
});
The problem I see with this is that it will involve updating two documents when the trade is accepted. Assuming that the trade is accepted, the ownerUser on each document will need to be changed and the trades array will need to be cleared out.
It seems that to do this you'd want the changes to be in some sort of "Transaction" so that if one didn't update for some reason, then the other wouldn't either.
Is this a typical way to model this type of situation? What to do about the "Transaction" part of the situation?
There is no way to do a transaction including multiple documents in MongoDB.
You might consider a separate Trade collection with documents like:
{
book: ...,
ownerUser: ...,
buyerUser: ...,
status: 'pending'
dateSold: null
}
When the trade is approved you can change this document first, then update any related documents next. Should something else fail, this document would decide whether the transaction had actually happened.
When creating a document with nested objects (e.g. an array of objects), each object is given its own _id. For example, my schema looks like this:
mongoose = require "mongoose"
Schema = mongoose.Schema
schema = new Schema
name:
type: String
required: true
unique: true
trim: true
lists: [
list:
type: Schema.Types.ObjectId
required: true
ref: "List"
allocations: [
allocation:
type: Number
required: true
]
]
createdAt:
type: Date
default: Date.now
updatedAt:
type: Date
# Ensure virtual fields are serialised.
schema.set "toJSON",
virtuals: true
exports = module.exports = mongoose.model "Portfolio", schema
Every object in the lists array is given an _id, as is every allocation object in the lists.allocations array, when documents are eventually created. This seems like overkill and bloats the document, but is there a reason MongoDB (or Mongoose) needs the document to contain this additional information? If not, I'd like to prevent it from happening so that the only _id is on the root document.
Furthermore, Mongoose automatically creates a virtual id for _id, which I need because my client code expects a field id. This is why I'm having virtuals returned with JSON. However, because there are _id fields all throughout the document, not just at the root, this virtual duplicates all of them. If there is no way to prevent the additional _id fields, how can I get a virtual to only apply only to the root document _id? Or if there is a better way to do what I'm trying to do with it, what would it be?
I have figured out a way to solve both issues with the same technique: by using explicit schemas for each nested object type and setting their _id and id options to false. It seems that when nesting objects that you define "inline", Mongoose creates schemas for each of those objects behind the scenes. Since the default for a schema is _id: true and id: true, they will get an _id as well as have a virtual id. But by overriding this with an explicit schema, I can control the _id creation. More code, but I get what I want:
mongoose = require "mongoose"
Schema = mongoose.Schema
AllocationSchema = new Schema
allocation:
type: Number
required: true
,
_id: false
id: false
mongoose.model "Allocation", AllocationSchema
ListsSchema = new Schema
list:
type: Schema.Types.ObjectId
required: true
ref: "List"
allocations: [AllocationSchema]
,
_id: false
id: false
mongoose.model "Lists", ListsSchema
PortfolioSchema = new Schema
name:
type: String
required: true
unique: true
trim: true
lists: [ListsSchema]
createdAt:
type: Date
default: Date.now
updatedAt:
type: Date
#neverfox thanks for info, I just adding the code for Nodejs
var _incidents = mongoose.Schema({
name : {type : String},
timestamp: {type : Number},
_id : {id:false}
});
_schema = mongoose.Schema({
_id: {type: String, required: true},
user_id: {type: String, required: true},
start_time: {type: Number, required: true},
incidents : [_incidents],
});