何时对大查询使用非规范化

问题描述 投票:0回答:1

我有一个名为

driverTourSchema
的模式,我是这样设计的

const driverTourSchema = mongoose.Schema({
    clientID: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Client',
        required: true,
    },

    userID: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User',
        required: true,
    },
    liters: {
        type: 'Number',
        // required: true,
    },
    recoveryDate: {
        type: Date,
        required: true,
    },
    isRecovered: {
        type: Boolean,
        default: false,
    },
    isScheduled: {
        type: Boolean,
    },
});

此集合的作用是保存司机(在本例中为应用程序的用户)将进行的旅行。

有时特定日期的驾车游览是由管理员安排的。

例如我们安排在8天后,然后在集合中保存一个driverTour文档,其中包含clientID,userID和指定日期的recoveryDate。

这种类型的司机旅行被称为定期旅行,因此司机知道他要去哪里。

但是在drive Tour中,司机可以停在管理员未指定的位置,因此在这种情况下我们也需要保存它,我也将其视为driveTour的一部分。

这就是我添加 isScheduled 属性以在两组之间产生差异的原因。


需要出示什么?

我有一个表格,其中列出了根据所选时间范围进行驾车旅行的用户。 我需要显示的数据是这样的

User(name), Client(name,also client address),  Total Clients(total of scheduled drive tours), totalRecoveries ( is total of recoveries made by user)

在客户总数中,我仅保存管理员创建的客户数量 因此,康复总数可能高于客户总数。

我是否需要重新设计架构以配合

Denormalization
,或者只是使用更复杂的查询。

我正在努力寻找最有效的方法。

我尝试过查找,但就资源而言这似乎很昂贵。

通过非规范化,我尝试创建另一个模式

const driverTourSummarySchema = mongoose.Schema({
    userID: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
    },
    clientID: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Client'
    },
    totalScheduled: Number,
    totalRecovered: Number
});

我写的查询是

return await DriverTour.aggregate([
            {
                $match: {
                    recoveryDate: {
                        $exists: true,
                        $gte: new Date(startDate),
                        $lte: new Date(endDate),
                    },
                },
            },
            {
                $lookup: {
                    from: 'users',
                    localField: 'userID',
                    foreignField: '_id',
                    as: 'user',
                },
            },
            {
                $unwind: '$user',
            },
            {
                $group: {
                    _id: {
                        userID: '$userID',
                        recoveryDate: '$recoveryDate',
                    },
                    user: { $first: '$user.name' },
                    userID: { $first: '$user._id'},
                    totalClients: { $sum: { $cond: { if: '$isScheduled', then: 1, else: 0 } } },
                    totalRecoveries: { $sum: { $cond: { if: '$isRecovered', then: 1, else: 0 } } },
                },
            },
            {
                $project: {
                    _id: 0,
                    recoveryDate: '$_id.recoveryDate',
                    user: '$user',
                    userID: '$userID',
                    totalClients: 1,
                    totalRecoveries: 1,
                },
            },
            {
                $sort: {
                    recoveryDate: -1,
                },
            },
        ]);

还有另一种方式我需要展示

Recovery Date, User , Number_OfClients, Total_Liters_Recovered

我应该在恢复时将其保存在另一个集合中还是什么?

什么是最有效的方法。 请给我一个例子。

node.js mongodb mongoose database-design
1个回答
0
投票

为了提高查询的性能,您可以考虑对架构进行非规范化。一种方法是创建一个名为 DriverTourSummarySchema 的新架构,其中包含以下字段:

const driverTourSummarySchema = mongoose.Schema({
    userID: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
    },
    clientID: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Client'
    },
    totalScheduled: Number,
    totalRecovered: Number,
    totalLitersRecovered: Number
});

此架构将存储来自 DriverTourSchema 的预聚合数据,包括计划和恢复的驾驶旅行总数,以及恢复的总升数。

查询

对架构进行非规范化后,您可以使用以下查询来检索所需的数据:

查询1:

return await DriverTourSummary.aggregate([
            {
                $match: {
                    userID: {
                        $in: userIDs,
                    },
                },
            },
            {
                $project: {
                    user: '$userID',
                    totalScheduled: 1,
                    totalRecovered: 1,
                },
            },
        ]);

此查询将返回 userIDs 数组中每个用户计划的和恢复的驾车游览总数。

查询2:

return await DriverTour.aggregate([
            {
                $match: {
                    userID: {
                        $in: userIDs,
                    },
                    recoveryDate: {
                        $gte: new Date(startDate),
                        $lte: new Date(endDate),
                    },
                },
            },
            {
                $lookup: {
                    from: 'driverTourSummaries',
                    localField: 'userID',
                    foreignField: 'userID',
                    as: 'driverTourSummary',
                },
            },
            {
                $unwind: '$driverTourSummary',
            },
            {
                $project: {
                    recoveryDate: 1,
                    user: '$userID',
                    numberOfClients: 1,
                    totalLitersRecovered: '$driverTourSummary.totalLitersRecovered',
                },
            },
            {
                $sort: {
                    recoveryDate: -1,
                },
            },
        ]);

此查询将返回指定时间范围内 userIDs 数组中每个用户的恢复日期、用户、客户端数量以及恢复的总升数。

© www.soinside.com 2019 - 2024. All rights reserved.