在嵌套对象猫鼬中按用户分组

时间:2019-10-23 20:15:27

标签: mongodb express mongoose mongodb-query

我想建立一个查询,让我得到类似的输出

{
"idOfUser":[Array of missions],
"idOfUser":[Array of mission]
}

实际上是按计划将用户按任务分组

每个用户都被分配了一个任务,对于计划而言,一项计划中可能会有很多任务。

我已经做的是

if (data["date"]) {
            Planning.find({ start: { $eq: new Date(Number(data["date"])) } }).populate('mission').exec((err, doc) => {
                if (!err)
                    return response(res, doc)
                else
                    return throwError(err, 404, next)
            })
}

这给了我类似

的输出
{ 
start:"some date",
end:"some date"
mission:[array of mission]
}

用户架构:

let UserSchema = new Schema({
    name: {
        type: Schema.Types.String,
        required: [true, "name must be required"],
    },
    email: {
        type: Schema.Types.String,
        required: [true, "email must be required"],
        unique: [true, "email already taken"],

    },
    password: {
        type: Schema.Types.String,
        required: true,
        validate: {
            validator: (pass) => pass.length >= 8,
            message: 'password must be consist of 8 characters'
        }
    },
    isAdmin: {
        type: Schema.Types.Boolean,
        default: false
    }
}); 

任务架构

let MissionSchema = new Schema({
    missionNotes: {
        type: Schema.Types.String,
        required: [true, "name is required"],
        // unique: [true, "must be unique"]
    },
    startDate: {
        type: Schema.Types.Date,
        required: [true, "startDate is required"],
    },
    endDate: {
        type: Schema.Types.Date,
        required: [true, "endDate is required"],

    },
    repeatInterval: {
        type: Schema.Types.Number,
        required: [true, "duration is required"],
    },
    pickupTime: {
        type: Schema.Types.Number,
        required: [true, "pickuptime is required"],
    },//minutes,
    flightNo: {
        type: Schema.Types.String,
        // required: [true, "flightNo is required"],
    },
    who: {
        type: Object,
        required: [true, "who is required"],
    },
    journey: {
        type: Object,
        required: [true, "journey is required"],
    },
    user: {
        type: Object,
        default: null
    },
    isAssign: {
        type: Schema.Types.Boolean,
        default: false,
    },
    info: {
        type: Schema.Types.String,
        // required: [true, "info is required"],
    },
    companyNotes: {
        type: Schema.Types.String
    },
    isCompleted: {
        type: Schema.Types.Boolean,
        default: false
    },
    car: {
        type: Object,
        default: null
    },
    fuel: {
        type: Schema.Types.Number,
        default: 0
    },
    extraExpense: {
        type: Schema.Types.Number,
        default: 0

    },
    crewInfo: {
        type: Schema.Types.String,
        default: ""
    },
    apt: {
        type: Schema.Types.String,
        default: ""
    },//actualpickuptime
    atad: {
        type: Schema.Types.String,
        default: ""
    },//actualtimeatdestination
    adt: {
        type: Schema.Types.String,
        default: ""
    },//actualdrivingtime
    acalpt: {
        type: Schema.Types.String,
        default: ""
    },//actualcalculatedpickuptime
    dap: {
        type: Schema.Types.String,
        default: ""
    },//delayafterpickup
    dacp: {
        type: Schema.Types.String,
        default: ""
    },//delayaftercalcpickup,
    isReminded: {
        type: Schema.Types.Boolean,
        default: false
    },

});

计划架构

let PlanningSchema = new Schema({
    title: {
        type: Schema.Types.String,
        // required: [true, "title is required"],
    },
    start: {
        type: Date,

        required: [true, "start is required"],
    },
    end: {
        type: Date,

        required: [true, "end is required"],

    },
    mission: [{ type: Schema.Types.ObjectId, ref: 'mission' }]


})

1 个答案:

答案 0 :(得分:0)

您可以使用MongoDB aggregation来实现。 首先完成所有计划的任务:

// You have to be in an async function to await like this
const plan = await Planning.find({ start: { $eq: new Date(Number(data["date"])) } });
const plannedMission = [];
plan.forEach(plan => { plannedMissions = [...plannedMissions, ...plan.mission] });

/* The plannedMission array should be something like this:
 [ "missionId1", "missionId2", "missionId3"]
*/

然后,我们按用户对任务进行分组,这是汇总的来源:

const pipeline = [ 
  { $match: { '_id': { $in: plannedMissions } } },
  { $group: { _id: "$user._id", missions: { $push: "$$ROOT"}  } }, 
];
// You have to be in an async function to await like this
const result = await db.missions.aggregate(pipeline);

/* result is an array object like this:
  [ 
    { "_id" : userId1, "missions" : ['mission1', 'mission2'] },
    { "_id" : userId2, "missions" : ['mission1', 'mission2'] }
   ] 
*/

// If you want to further reduce the result to just a single object, you can do this:
const missionsByUser = {};

result.forEach(res => userByMission[res._id] = res.missions);

/* missionsByUser should be something like this:
  { 
    "userId1": ['mission1', 'mission2'],
    "userId2": ['mission1', 'mission2'] 
  }
*/