Reputation: 47
I am trying to populate a field inside a two dimensional array with mongoose in NodeJS.
This is how is structured my translation data:
{
"_id" : ObjectId("5cc3fa08c2d98a3ac8e4889a"),
"translation" : [
[
{
"x" : "999",
"y" : "999",
"width" : "555",
"height" : "555",
"idVideo" : ObjectId("5cc401f319bac9285ce0a235")
},
{
"x" : "111",
"y" : "111",
"width" : "666",
"height" : "666",
"idVideo" : ObjectId("5cc401f319bac9285ce0a235")
}
]
],
"__v" : 2
}
TranslationSchema.js
const TranslationSchema = mongoose.Schema(
{
idDocument: {
type: Schema.Types.ObjectId,
ref: 'Document'
},
translation: {
type: [[TranslationCoordinateSchema]],
default: []
}
},
{
strict: true
}
);
TranslationCoordinateSchema.js
const TranslationCoordinateSchema = mongoose.Schema({
x: {
type: String
},
y: {
type: String
},
width: {
type: String
},
height: {
type: String
},
idVideo: {
type: Schema.Types.ObjectId,
ref: 'TranslationVideo'
},
_id: false
});
I tried many things but I don't know how to structure the path as it is a two dimensional array. For exemple I tried:
Translation.findById(idTranslation).populate({
path: 'translation.idVideo',
model: 'TranslationVideo'
});
and
Translation.findById(idTranslation).populate({
path: 'translation.translation.idVideo',
model: 'TranslationVideo'
});
and maybe
Translation.findById(idTranslation).populate({
path: 'translation..idVideo',
model: 'TranslationVideo'
});
I expect to populate idVideo so I can return all the containing data but instead I have :
"data": [
{
"type": "translations",
"id": "5cc3fa08c2d98a3ac8e4889a",
"translation": [
[
{
"x": "999",
"y": "999",
"width": "555",
"height": "555",
"idVideo": "5cc401f319bac9285ce0a235"
},
{
"x": "111",
"y": "111",
"width": "666",
"height": "666",
"idVideo": "5cc401f319bac9285ce0a235"
}
]
],
}
]
Solution
Thank you Moad Ennagi for the solution. I just edited his solution to make it work with ASYNC/AWAIT.
static async findByIdAndPopulateVideos(idTranslation) {
let count;
let arr = [];
if (!(count = await Translation.findById(idTranslation))) {
return;
}
for (let i = 0; i < count.translation.length; i++) {
arr.push(`translation.${i}.idVideo `); // Don't delete the last space !
}
return await Translation.findById(idTranslation).populate({
path: arr.join(''),
model: 'TranslationVideo'
});
}
Upvotes: 1
Views: 1634
Reputation: 1073
You need to specify the position of the subarray then populate the objects within:
Translation.findById(idTranslation).populate('translation.0.idVideo')
This would work for the first (subarray [0]), you would need to loop inside the array if you want to populate other subarrays, I don't think mongoose comes with any built in positional operator ($[] as in mongoDB native Client).
Example with a loop
Here is a full working example, I tried to mimic your schemas:
const fooSchema = new mongoose.Schema({
name: String
});
const Foo = mongoose.model('Foo', fooSchema);
const barSchema = new mongoose.Schema({
x: String,
y: String,
fooId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Foo'
}
});
const Bar = mongoose.model('Bar', barSchema);
const totoSchema = new mongoose.Schema({
bar: [[barSchema]]
});
const Toto = mongoose.model('Toto', totoSchema);
// seeds
let foo = new Foo({name: 'foo'});
let bar, bar2;
foo.save().then(val => {
bar = new Bar({x: '1', y: '1', fooId: val._id});
bar2 = new Bar({x: '2', y: '2', fooId: val._id});
toto = new Toto({bar: [[bar, bar2], [bar, bar2]]}).save(); // pushing the same objects(bar and bar2) out of lazyness
});
// A find query with a loop to construct paths to be populated
Toto.findById(/* totoId */)
.exec()
.then(toto => {
let arr = [];
for(let i = 0; i <= toto.bar.length; i++) { // length of the array (1st dimension)
arr.push(`bar.${i}.fooId `); // constrtucting the path
}
toto.populate(arr.join(''), (err, doc) => {
if(err) throw err;
else console.log(toto.bar);
});
})
.catch(err => console.log(err));
/* Output
[
[
{
"_id":"5cc472cd90014b60f28e6cb4",
"x":"1",
"y":"1",
"fooId":{"_id":"5cc472ca90014b60f28e6cb3","name":"foo","__v":0}
},
{
"_id":"5cc472cd90014b60f28e6cb5",
"x":"2",
"y":"2",
"fooId": {"_id":"5cc472ca90014b60f28e6cb3","name":"foo","__v":0}
}
],
[
{
"_id":"5cc472cd90014b60f28e6cb4",
"x":"1",
"y":"1",
"fooId": {"_id":"5cc472ca90014b60f28e6cb3","name":"foo","__v":0}
},
{
"_id":"5cc472cd90014b60f28e6cb5",
"x":"2",
"y":"2",
"fooId": {"_id":"5cc472ca90014b60f28e6cb3","name":"foo","__v":0}
}
]
]
*/
I hope this helps ;)
Upvotes: 2