Mongoose - Defining child's ObjectID in another Schema - node.js

There is a similar thread # Mongoose variable key name. However, he goes with another method instead of solving this. The other method is the OR part of my title.
EDIT - IGNORE THIS SECTION, I AM USING THE ALTERNATIVE NOW. Issue now lays with referencing a child's Object ID elsewhere.
I have the following array:
selections: [{
4433d18d31f3775756ac2a70: "542e91aa31f3775756abccda"},
{4433d18d31f3775756ac2a71: "542e916c31f3775756abccd8"},
{4433d18d31f3775756ac2a72: "542e934231f3775756abccdb"
}]
My schema is currently as follows:
selections: {
<something>: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Selection'
}
}
In place <something>, is there a way of essentially saying "I don't care what's here"?
ALTERNATIVELY, as this doesn't seem possible after scouring the internet, I can have the following schema:
selections: {
pid: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Competition.CHILD'
}
selection: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Selection'
}
}
But the issue here is that ObjectID that is being used where <something> is a child schema inside of the schema Competition, and I can't find a way of saying that for the Object ID.
Any advice/help would be great please. Ideally I'd prefer the first solution but I understand it may not be possible. Thanks!

Use an array of objects with optional (but fixed) keys:
selections: [{
selection: {type: ObjectId, ref: 'Selection'},
child: {type: ObjectId, ref: 'Competition.CHILD'}
}]
This will enable you to do better queries, use mongoose population, etc.

Related

Mongoose: Pushing values to an array inside a nested object

I have been searching for an answer for this for hours - there seem to be some similar questions without a working answer - so if you can help me solve it then you can have my car, my house and my first born - whatever you want!
When I create a record for the model below, I need a way to insert values to the participants nested array:
const recordSchema = new Schema (
{record:
[
{
eventDate: Date,
game: {
type: Schema.Types.ObjectId
,ref: "Game"
},
winner: {
type: Schema.Types.ObjectId
,ref: "Member"
},
particpants: [
{
type: Schema.Types.ObjectId
,ref: "Member"
}
]
},
{
timestamps: true,
}
],
}
)
Creating a record works fine for all fields except participants, which remains unpopulated:
Record.create({record: { game: game, winner: winner, participants: participants }})
I have tried several methods to try to get to that nested array and (for example) update after creation, but so far I haven't been able to get there. Keep in mind this needs to create programatically - I can't hard code in any values.
Many, many, many thanks if you are able to help me with this.
Edit: adding the data being input as comment said this would be useful:
console logging the variables right before the create returns the following: game: '6220ca4d8179d6685b4c05b7', winner: '6225ed9f21a3b31c86098b8d', participants: [ '6225ec458e34373cf7337d68', '6225ed9f21a3b31c86098b8d' ]
You have a typo in your schema, as you can see your schema expects particpants but in your .create() you are passing participants.
You are missing an i after c in schema.
participants: [{ type: Schema.Types.ObjectId, ref: "Member" }]

Mongodb Relationship: Posts and Comments (ref v sub-documents)

I know there are a lot of similar questions, but they're too old and since Mongodb has evolved alot for last 5-6 years I am looking for a good schema design.
Goal: I want to have a post with comments by users.
What I have designed so far is:
Separate post model:
const projectSchema = new mongoose.Schema({
user: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'User' },
title: { type: String, required: true },
image: { type: String, default: undefined },
description: { type: String, required: true, minLength: 200, maxlength: 500 },
comments: [{
type: mongoose.Schema.Types.ObjectId, ref: 'Comment'
}],
state: { type: Boolean, default: true },
collaborators: { type: Array, default: [] },
likes: { type: Array, default: [] }
})
And a separate comments model:
const commentSchema = new mongoose.Schema({
comment: { type: String, required: true },
project: { type: String, required: true, ref: 'Project' },
user: { type: String, required: true, ref: 'User' }
})
The reason I am going for the relational approach is because if the comments increase to say 10,000 in number, it will increase the size of schema by alot.
This way, no matter how many comments we can populate them using their IDs, also, we will have different collection for comments iself.
Reference : one-to-many
Is this a good approach for my project?
The way I am querying the comments from one single post:
const project = await Project.findById(
new mongoose.Types.ObjectId(req.params.projectId)
).populate({
path: 'comments',
populate: { path: 'user' }
}).lean()
Whether it's a good design depends how many comments per post do you expect, and what query will be performed on your app.
There's a good blog from mongodb.com on how to design your database schema
The common design is:
One to Few (Use embed)
One to Many (Use embed reference)
One to squillions (The usual relational database one-to-many approach)
Summary is:
So, even at this basic level, there is more to think about when designing a MongoDB schema than when designing a comparable relational schema. You need to consider two factors:
Will the entities on the ā€œNā€ side of the One-to-N ever need to stand alone?
What is the cardinality of the relationship: is it one-to-few; one-to-many; or one-to-squillions?
Based on these factors, you can pick one of the three basic One-to-N schema designs:
Embed the N side if the cardinality is one-to-few and there is no need to access the embedded object outside the context of the parent object
Use an array of references to the N-side objects if the cardinality is one-to-many or if the N-side objects should stand alone for any reasons
Use a reference to the One-side in the N-side objects if the cardinality is one-to-squillions
There is also a blog about advanced schema design which is worth the read.
You seems to be using the two-way referencing approach.
The difference between yours and one-to-squillions is you are not only storing post id reference on comment document, but also storing comment ids as reference in post document, while one-to-squillions will only stores project id reference in comment document.
Using your approach will be better if you need to get comment ids of a post. But the disadvantage is you need to run two queries when deleting or creating a comment, one to delete / create comment id from post, and the other one to delete / create the comment document it self. It's also will be slower to find "which post belongs to given comment id".
While using one-to-squillions would gives you worse performance when performing a query to get comments by post id. But you can mitigate this by properly indexing your comment collection.

How to use $push inside $set in mongoose?

I'm using express-restify-mongoose library to have rest endpoints agaist mongoose.
I have schema looks like this:
const BookSchema = new Schema(
{
name: { type: String },
items: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Book' }],
}
);
So I send http patch request: { name: 'blabla' } and it change the name as expect.
But when I want to add item to items array like { items: ["5dd138199f6ecb3990360328"] } its replace the entire object (with one 5dd138199f6ecb399036032d item).
After I digging in the source code I see here the function uses findOneAndUpdate and $set.
So my question is there is any way to use $push or any function/property in the $set value?
I can't add to this library, but maybe there is any workaround solution here?
I think the closest solution in mongoose is to use Set Elements in Arrays:
"items.1": "5dd138199f6ecb3990360355"
Which will add to array, but you have to pass the position.

MongoDB embedded document as key-val array

I'm trying to use mongoose to represent an association between 3 schemas:
Schema1: {
//fields
}
Schema2: {
//fields
}
Scehma3: {
//fields
- [Scehma1:Scehma2] - collection of key-val elements
where the key is a ref to schema1 and val is ref to scehma2
}
Does mongoose support this king of association without creating a schema4?
You can't create ambiguous keys in mongoose because its whole purpose is to handle your document structure for you. What you can do, however, is create an array of objects.
Schema4: {
schemaRefs: [{
refToSchema1: {type: mongoose.Types.ObjectId, ref: 'Schema1'},
refToSchema2: {type: mongoose.Types.ObjectId, ref: 'Schema2'}
}]
}
For future reference it's far easier to understand your question when you provide real examples rather than false names. Even if you falsify your example (e.g. some relationship between restaurants and customers or something) it's much easier to understand the relationship you're trying to make.

DB-ref in mongoose without Schema.ObjectId?

in my code people can follow other people.
So far everything is ok apart from this fact: in the userScheme I have this field.
, following: [{ type: Schema.ObjectId, ref: 'Users' }]
Since every user has an username, it's more versatile for me to use dbref with the username.
is there a way to do something like this?
, following: [{ type: Users.username, ref: 'Users' }]
Many thanks,
g
No, only ObjectId values that refer to the _id property of another collection can be used as refs.
Confirmed in the source code.
You can only reference via ObjectId to a collection like your first code snippet.
[{ type: Schema.ObjectId, ref: 'Users' }]
When making a query with populate(), you can specify the fields you want to return. In your case, it woud look something like
User.find({}).populate('following', 'username').exec(function(err,doc) {});
Each object in the following array would look like
{ _id: 'xxxxxxxxxx', username: 'xxxxxxxx' }
mongoose's populate function is mongodb's lookup in the abstract but populate only creates refs to object id but if you are sure then you will have a unique username for every user and then if you want to populate data using username then you can use lookup and result will be the same.

Resources