Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can we use $embed for array of array field? #31

Closed
samseralam opened this issue Aug 21, 2017 · 2 comments
Closed

can we use $embed for array of array field? #31

samseralam opened this issue Aug 21, 2017 · 2 comments

Comments

@samseralam
Copy link

samseralam commented Aug 21, 2017

@JKHeadley would like to use $embed for getting inner array field data.
my schema is like this...
facilitiesPerFloor: [{
suiteInfo: {
floorNo: {
type: Types.Number
}
},
facilities: [{
type: Types.ObjectId,
ref: "facility"
}]
}]

Holding Data
"facilitiesPerFloor": [
{
"_id": "5996d930daec05116aed9e35",
"facilities": [
"5996d83a0c2b83113cdfd40c",
"5996d83a0c2b83113cdfd41c"
],
"suiteInfo": {
"floorNo": 1
}
}
]

Note: facilitiesPerFloor contains facilities array where multiple facility can be. Now how i can use $embed for getting/populating second level of facilities data.

Thanks.

@JKHeadley
Copy link
Owner

You cannot directly use $embed here to populate the facilities. You can however set up a dummy association and process your own $embed query using a post middleware function. Below is one example of how to implement this. It is by no means the most efficient solution and I can't guarantee its complete functionality but I had some success with it.

NOTE: the below code will only work for rest-hapi v0.19 and higher

'use strict';

const Q = require('q');
const _ = require('lodash');
const RestHapi = require('rest-hapi');

module.exports = function (mongoose) {
    var modelName = "building";
    var Types = mongoose.Schema.Types;
    var Schema = new mongoose.Schema({
        
        facilitiesPerFloor: [{
            suiteInfo: {
                floorNo: {
                    type: Types.Number
                }
            },
            facilities: [{
                type: Types.ObjectId,
                ref: "facility"
            }]
        }]

    }, { collection: modelName });

    Schema.statics = {
        collectionName: modelName,
        routeOptions: {
            associations: {
                //EXPL: dummy association that allows for the 'facilitiesPerFloor' value in the $embed parameter
                facilitiesPerFloor: {
                    type: "_MANY",
                    model: "facility",
                    allowAdd: false,
                    allowRemove: false,
                    allowRead: false
                }
            },
            list: {
                post: function (query, result, Log) {
                    const Facility = mongoose.model('facility');

                    if (!_.isArray(query.$embed)) {
                        query.$embed = [query.$embed]
                    }
                    if (query.$embed.indexOf('facilitiesPerFloor') > -1) {
                        //EXPL: first collect all the facility ids
                        const ids = result.reduce(function(ids, document) {
                            let docIds = [];
                            if (document.facilitiesPerFloor) {
                                docIds = document.facilitiesPerFloor.reduce(function(docIds, floor) {
                                    return docIds.concat(floor.facilities);
                                }, [])
                            }
                            return ids.concat(docIds);
                        }, []);

                        //EXPL: next fetch the facility documents and replace the ids with the matching documents
                        return RestHapi.list(Facility, { "_id": ids }, Log)
                            .then(function(facilities) {
                                result = result.map(function(document) {
                                    if (document.facilitiesPerFloor) {
                                        document.facilitiesPerFloor = document.facilitiesPerFloor.map(function(floor) {
                                            floor.facilities = floor.facilities.map(function(facilityId) {
                                                let facility = facilities.docs.find(function(facility) {
                                                    return facility._id.toString() === facilityId.toString();
                                                });
                                                return facility;
                                            });
                                            return floor;
                                        });
                                    }
                                    return document;
                                });
                                return result;
                            })
                    }
                    else {
                        return Q.when(result);
                    }
                }
            }
        }
    };

    return Schema;
};

@samseralam
Copy link
Author

Thanks @JKHeadley
After creating association with facility model it works fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants