I have a type collection that stores field informations. Each field has a type: Input, SelectBox, MultiSelect. Some field types have predefined options with key and label.
Here is an example of a type document:
{
id: 't-123'
attributes: [
{
id: 'a-1',
type: 'INPUT'
},
{
id: 'a-2',
type: 'SELECT',
option: [
{key: 'DE', label: 'Germany'},
{key: 'US', label: 'United States'}
]
}
]
}
Additionally, I have a form collection that references the type collection and stores all filled fields from a user.
Here is an example of a form document:
{
id: 'f-1',
type: 't-123',
values: [
{attribute: 'a-1', value: 'my random string'},
{attribute: 'a-2', value: 'DE'}
]
}
Now, I am trying to query the form collection and automatically add the choosen key/label object from the type collection for fields with type: SELECT. I am wondering if I can do this in mongoDB or only in node.js.
Here is my desired result:
{
id: 'f-1',
type: 't-123',
values: [
{attribute: 'a-1', value: 'my random string'},
{attribute: 'a-2', value: {key:'DE', label:'Germany'}}
]
}
So the query needs to check if the attribute.type is equal to 'SELECT', and find the related object from the options array, based on the key stored in the form. Else it takes the value stored in the form document.
Can I do anything like this within my MongoDB query or do I have to loop through my database results and manipulate the data manually ? THX!!
Related
Consider there is documents like this in DB:
{
name: 'my list',
items: [
{ type: 'book', id: 5364 },
{ type: 'car', id: 354 },
{ type: 'laptop', id: 228 }
]
}
I need to grab data of each item from its own collection, based on type value.
I searched about it but couldn't figure out the correct approach.
Expected output:
{
name: 'my list',
items: [
{ type: 'book', id: 5364, data: [{...}] },
{ type: 'car', id: 354, data: [{...}] },
{ type: 'laptop', id: 228, data: [{...}] }
]
}
Mongoose schema of first collection (above):
{
name: String,
items: {
type: Array,
default: []
}
}
And other collections that must be looked up has corresponding _id field.
There are a few different ways to do this. To be most similar to what you have currently, you just need to make one small change. type is a keyword in Mongoose, so if you want to have a field in your schema which is actually called "type", you need to use the word twice. Once for the Mongoose keyword and again to define your schema.
{
name: String,
items: [{
type: { type: String},
id: Number,
data: []
}]
}
If the data field is coming from another collection, you could use a reference and then call populate() on your find method.
// ItemSchema
{
name: String,
items: [{
type: { type: String },
id: Number,
data: [{
type: Schema.Types.ObjectId,
ref: 'OtherSchemaName'
}]
}]
}
// Find Method with populate
const myList = await ItemSchema.find({type: "book"}).populate('data')
// Result
{
name: 'my list',
items: [
{ type: 'book', id: 5364, data: [{...}] },
]
}
Just like the title suggests, is there a way to populate an array using mongoose and return the populated documents, along side the array items that failed to find an associated document.
Example, I have the following Model and example document. The document in question has two users (stored in array). One of the emails, is associated with a user in the database and the other is not. If I run virtual populate on this array, I am only given the one user document where the reference was found.
Here is my Model
const organizationSchema = new Schema({
name: {
type: String,
required: true
},
users: [String],
}, { timestamps: { createdAt: 'created_at' } });
organizationSchema.virtual('users_populated',{
ref: 'users',
localField: 'users',
foreignField: 'email'
});
Example Document
{
name: "Test Organization", users:["email1#gmail.com",
"email2#gmail.com"]
}
What i'm looking to do
If one of the user's doesn't exist, I would like it to return this:
[{_id: 109753097121092, name: 'steve', email: 'email1#gmail.com'}, "email2#gmail.com"]
Or even:
[{_id: 109753097121092, name: 'steve', email: 'email1#gmail.com'}, {email: "email2#gmail.com"}]
What i'm getting (notice the entry that failed to populate is missing:
[{_id: 109753097121092, name: 'steve', email: 'email1#gmail.com'}]
Here is an example of a type document:
{
id: 't-123'
attributes: [
{
id: 'a-1',
type: 'INPUT'
},
{
id: 'a-2',
type: 'SELECT',
option: [
{key: 'DE', label: 'Germany'},
{key: 'US', label: 'United States'}
]
}
]
}
Additionally, I have a form collection that references the type collection and stores all filled fields from a user.
Here is an example of a form document:
{
id: 'f-1',
type: 't-123',
values: [
{attribute: 'a-1', value: 'my random string'},
{attribute: 'a-2', value: 'DE'}
]
}
Now, I am trying to query the form collection and automatically add the choosen key/label object from the type collection for fields with type: SELECT.
Here is my desired result:
{
id: 'f-1',
type: 't-123',
values: [
{attribute: 'a-1', value: 'my random string'},
{attribute: 'a-2', value: {key:'DE', label:'Germany'}}
]
}
Here is an example of a type document:
{
id: 't-123'
attributes: [
{
id: 'a-1',
type: 'INPUT'
},
{
id: 'a-2',
type: 'SELECT',
option: [
{key: 'DE', label: 'Germany'},
{key: 'US', label: 'United States'}
]
}
]
}
Additionally, I have a form collection that references the type collection and stores all filled fields from a user.
Here is an example of a form document:
{
id: 'f-1',
type: 't-123',
values: [
{attribute: 'a-1', value: 'my random string'},
{attribute: 'a-2', value: 'DE'}
]
}
Now, I am trying to query the form collection and automatically add the choosen key/label object from the type collection for fields with type: SELECT.
Here is my desired result:
{
id: 'f-1',
type: 't-123',
values: [
{attribute: 'a-1', value: 'my random string'},
{attribute: 'a-2', value: {key:'DE', label:'Germany'}}
]
}
Consider the following Mongoose schema:
new mongoose.Schema({
attributes: [{
key: { type: String, required: true },
references: [{
value: { type: String, required: true },
reference: { type: mongoose.Schema.Types.ObjectId, required: true }
}]
}
});
A document that follows this schema would look like this:
{
attributes: [
{
key: 'age', references: [{ value: '35', reference: 298387adef... }]
},
{
key: 'name', references: [{
value: 'Joe', reference: 13564afde...,
value: 'Joey', reference: 545675cdab...,
}
...
]
}
I'd like to select attributes according to the following conditions:
- the key is name for example
- the attribute with key name has a least one reference with a value Joe.
Ideally, I'd like to AND-chain many of these conditions. For example, {'name': 'Joe'} and {'age': '35'}.
I can't seem to find a way of doing that Mongoose. I've tried the following Mongoose queries without any good results (it gives either false positives or false negatives):
// First query
query.where('attributes.key', attribute.key);
query.where('attributes.references.value', attribute.value);
// Second
query.and([{ 'attributes.key': attribute.key }, { 'attributes.$.references.value': attribute.value }]);
// Third
query.where('attributes', { 'key': attribute.key, 'references.value': { $in: [attribute.value] }});
So how do I do it?
You can use elemMatch to find docs that contain an attributes element that matches multiple terms:
query.elemMatch(attributes, { key: 'name', 'references.value': 'Joe' })
You can't chain multiple elemMatch calls together though, so if you want to AND multiples of these you'd need to explicitly build up a query object using $and and $elemMatch instead of chaining Query method calls.