MongoDB查找嵌套查询以填充对象

时间:2019-03-03 20:21:52

标签: node.js mongodb

我正在用猫鼬构建一个node.js应用程序,但是我目前正试图尝试正确查询MongoDB ...

我目前有3种MongoDB模型:

admin/Manage

1个房间多排,1个座位多排。

我可以使用以下查询来获取包含所有行的Room对象:

import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *

import ctypes
import ctypes.wintypes

user32 =  ctypes.windll.user32
HUD_WIDTH = 100
HUD_HEIGHT = 50 
WINDOW_NAME = "Window name" #Replace this by the name of an opened window 

EVENT_OBJECT_LOCATIONCHANGE = 0x800B
EVENT_SYSTEM_FOREGROUND = 0x0003
WINEVENT_OUTOFCONTEXT = 0x0000
EVENT_SYSTEM_MINIMIZEEND = 0x0017

class Hud(QLabel):
    def __init__(self,window_handle):
        super().__init__()
        self.initUI()
        self.window_handle = window_handle
        rect = ctypes.wintypes.RECT()
        user32.GetWindowRect(window_handle,ctypes.byref(rect))
        self.window_x = rect.left
        self.window_y = rect.top
        self.setFollowWindow()

def initUI(self):
    self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint)   
    self.resize(HUD_WIDTH,HUD_HEIGHT)   
    p = self.palette()
    p.setColor(self.backgroundRole(), Qt.black)
    p.setColor(self.foregroundRole(),Qt.white)
    self.setPalette(p)  
    self.setWindowOpacity(0.7)
    self.setText("Hello")
    self.setAlignment(Qt.AlignCenter)
    self.show()

def mousePressEvent(self,event):
    self.click_x_coordinate = event.x()
    self.click_y_coordinate = event.y()

def mouseMoveEvent(self,event):
    self.move(event.globalX()-self.click_x_coordinate,event.globalY()-self.click_y_coordinate)

def setFollowWindow(self):
    WinEventProcType = ctypes.WINFUNCTYPE(
        None, 
        ctypes.wintypes.HANDLE,
        ctypes.wintypes.DWORD,
        ctypes.wintypes.HWND,
        ctypes.wintypes.LONG,
        ctypes.wintypes.LONG,
        ctypes.wintypes.DWORD,
        ctypes.wintypes.DWORD
    )
    def callback(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime):
        if idObject != -9: #Avoids mouse events
            if event == EVENT_OBJECT_LOCATIONCHANGE and hwnd == self.window_handle:
                rect = ctypes.wintypes.RECT()
                user32.GetWindowRect(hwnd,ctypes.byref(rect))
                self.move(self.x() + rect.left - self.window_x,self.y() + rect.top - self.window_y)
                self.window_x = rect.left
                self.window_y = rect.top 
            elif event == EVENT_SYSTEM_FOREGROUND or event == EVENT_SYSTEM_MINIMIZEEND:
                if hwnd == self.window_handle:
                    user32.SetWindowPos(self.winId().__int__(),-1,self.x(),self.y(),self.width(),
                            self.height())

    self.WinEventProc = WinEventProcType(callback)        
    user32.SetWinEventHook.restype = ctypes.wintypes.HANDLE
    self.hook = user32.SetWinEventHook(
        EVENT_SYSTEM_FOREGROUND,
        EVENT_OBJECT_LOCATIONCHANGE,
        0,
        self.WinEventProc,
        0,
        0,
        WINEVENT_OUTOFCONTEXT
    )
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow,self).__init__()
        self.initUI()
    def initUI(self):
        self.launch_hud_button = QPushButton("Launch HUD",self)
        self.launch_hud_button.clicked.connect(self.launchHud)
        self.show()
    def launchHud(self):
        window_handle = user32.FindWindowW(0,WINDOW_NAME)
        if window_handle != 0 :
            self.hud = Hud(window_handle)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    sys.exit(app.exec_())

但是,我找不到用于获取每一行席位的解决方案,异步处理正在破坏每次尝试的逻辑。 我已经尝试过for循环,async.waterfall(),Promise.all(),但我每次都失败。

有人烦我吗?谢谢!

备注:如评论和可能的答案中所建议,我应该仅使用一种模型,我已经拥有那种模型,但是在更新多个席位时遇到了问题。将对此进行进一步的研究。

1 个答案:

答案 0 :(得分:0)

通过正确设置引用ref并稍微修改模型,您可以更轻松地实现此目的。但是,我将修改您的代码以向您展示如何按照您的方法进行操作,然后在引用字段中提供一个关于猫鼬填充的示例:

您采用纯模式的方法

在进入代码之前,我将用.toObject()替换文档上的.lean()调用,这是一种猫鼬方法,它在查询文档并优化查询后为您执行此操作,因为它跳过了将MongoDB原始文档转换为Mongoose对象的过程:

// Encapsulate this with try-catch
const room = await Room.findOne({ name: req.params.room_name }, { __v: 0 }).lean().exec()
const rows = await Row.find({ roomid: room._id }, { roomid: 0, __v: 0 }).lean().exec()

// This is a blocking loop
for (let row of rows) {
    const seats = await Seat.find({ rowid: row._id }, { rowid:0, __v: 0 }).lean().exec()
    row.seats = seats
}

room.rows = rows
res.json(room)
// Close try-catch

现在可以使用Promise.all()对for循环进行一些优化,它将异步执行每个循环迭代:

await Promises.all(rows.map(async (row) => {
    const seats = await Seat.find({ rowid: row._id }, { rowid:0, __v: 0 }).lean().exec()
    row.seats = seats
})

猫鼬人口法

让我们通过直接简单地自然而然的推理来重新定义您的模型:

  

1个房间有很多行

然后,您可能希望您的房间具有一系列的行ID,如下所示:

Room.model

const roomModel = mongoose.model('Room', new mongoose.Schema({
    name: String,
    rows: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Row'
    }]
))

进一步

  

一排有很多座位

Row.model

const rowModel = mongoose.model('Row', new mongoose.Schema({
    seats: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Seat'
    }],
    name: String
))

最后,您的座位模型将非常简单:

Seat.model

const seatModel = mongoose.model('Seat', new mongoose.Schema({
    position: Number,
    number: Number
))

现在查询简单得多

const room = await Room.findOne({ name: req.params.room_name }, { __v: 0 })
    .populate({
        path: 'rows',
        select: '-__v', // Remove __v field
        populate: {
            path: 'seats',
            select: '-__v' // Remove __v field
    }).lean().exec()

res.json(room)

如您所见,采用这种方法并正确设计数据模型,可以更简单但是,这还不是您希望在MongoDB中设计数据模型的方式,如Neill Lunn在评论中所述。与其定义3个简单的数据模型,不如只定义1个模型,其中包含行和席位模式的嵌入式子文档数组。与此类似:

Room.model

mongoose.model('Room', new mongoose.Schema({
    name: String,
    rows: [{
        name: String,
        seats: [{
            position: Number,
            number: Number,
    }]
})