Skip to main content
 首页 » 编程设计

mongodb之如何在 MongoDB 中运行 NOT EXISTS 查询

2024年02月20日26开发

我有两个收藏pagelikes。在这两个集合中都有字段 pageIdlikes 也有字段 userName

如果likes集合包含一对pageId/userName,则表示该页面被特定用户喜欢。

如何运行查询来返回特定用户不喜欢的任意一页?

在 SQL 中,这看起来像这样:

SELECT * 
FROM page 
WHERE NOT EXISTS (SELECT 'a' FROM likes WHERE (likes.pageId = page.pageId) AND (likes.userName = 'userName')) 
LIMIT 1 

我考虑过使用 $exists 运算符,但是 here我读到它的含义与同名的 SQL 操作不同,我必须使用 $in 运算符。

我可以

  1. 找出特定用户喜欢的所有页面并将其保存在列表中
  2. 然后在 page 上运行查询,该查询应返回第一个页面,该页面未包含在列表中。

我正在犹豫是否要以这种方式实现它,因为它对我来说似乎效率很低(我在步骤 2 中只需要一页,但要获得该页,我需要遍历用户的所有点赞)。

请您参考如下方法:

在 3.6 版本中,我们提供了新的 $lookup 管道语法,允许您对相关文档执行管道。您可以使用它来查找符合您特定条件的相关文档。将其与更多步骤相结合,您可以构造一个 NOT EXISTS 查询。

  1. 查找相关对象
  2. 使用 $expr { $and: [] } 将连接与附加约束结合起来
  3. 使用 $limit: 1 进行优化,因为我们只关心是否存在
  4. $match 其中连接属性 $exists: false
  5. 为了更好地衡量,$project 消除了空集合

例如,要查询特定用户没有点赞的页面,请按如下方式构建管道:

db.page.insertOne({ pageId: 1 }) 
db.page.insertOne({ pageId: 2 }) 
db.page.insertOne({ pageId: 3 }) 
db.likes.insertOne({ pageId: 1, userName: "Pinky" }) 
db.likes.insertOne({ pageId: 2, userName: "Pinky" }) 
db.likes.insertOne({ pageId: 2, userName: "Brain" }) 
db.likes.insertOne({ pageId: 3, userName: "Brain" }) 
 
db.page.aggregate([{ 
    "$lookup": { 
        "from": "likes", 
        "let": { 
            "pageId": "$pageId" 
        }, 
        "pipeline": [{ 
            "$match": { 
                "$expr": { 
                    "$and": [ 
                        { "$eq": [ "$pageId", "$$pageId" ] }, 
                        { "$eq": [ "$userName", "Pinky" ] } 
                    ] 
                } 
            } 
        }, { 
            "$limit": 1 
        }], 
        "as": "likes" 
    } 
}, { 
    "$match": { 
        "likes.pageId": { "$exists": false } 
    } 
}, { 
    "$project": { 
        "likes": false 
    } 
}])