我正在try 从购物车集合的物品数组中查找(并更新)特定对象. 购物车文档看起来像这样

{
    _id: ObjectId("661fb9ddc2b236ae8703ba92"),
    display_id: '38bd6126-02a1-47b9-b567-00aaf2eb076f',
    user_id: ObjectId("661137f22a31832ceb92ddbc"),
    items: [
      {
        product_id: ObjectId("6622376051d5886f39ac7365"),
        size: ObjectId("660d444d0d7716ee24129675"),
        qty: 3
      },
      {
        product_id: ObjectId("662214f8cc5306f999369e99"),
        size: ObjectId("660d444d0d7716ee24129675"),
        qty: 2
      },
      {
        product_id: ObjectId("662214f8cc5306f999369e99"),
        size: ObjectId("660d444d0d7716ee24129674"),
        qty: 2
      }
    ],
    __v: 4
  }

我try 运行的查询是

db.carts.find({user_id: new ObjectId("661137f22a31832ceb92ddbc"), "items.product_id": new ObjectId("662214f8cc5306f999369e99"), "items.size":new ObjectId("660d444d0d7716ee24129675")}, {"items.$":1})

或者是mongoose

const doc = await Cart.findOne({
                user_id: user_id,
                "items.product_id": product_id,
                "items.size": oldSize
            },{"items.$":1})

理想情况下它应该返回这个对象:

{
 product_id: ObjectId("662214f8cc5306f999369e99"),
 size: ObjectId("660d444d0d7716ee24129675"),
 qty: 2
}

但它返回这个:

{
 product_id: ObjectId("6622376051d5886f39ac7365"),
 size: ObjectId("660d444d0d7716ee24129675"),
 qty: 3
},

请告诉我我做错了什么.

推荐答案

处理子文档时,查询可能会令人困惑.对于您当前的查询,它实际上是以AND方式查询3件事:

  1. 任何包含user_id: 661137f22a31832ceb92ddbc的文档
  2. 任何包含either 1个子文档items包含product_id: 662214f8cc5306f999369e99的文档
  3. 任何包含either 1个子文档items包含size: 660d444d0d7716ee24129675的文档

请注意,对于#2和#3,它们不需要是同一个子文档.换句话说,也可以返回具有仅满足#2或#3的2个独立子文档的文档.

对于您的情况,您的文档中包含同时满足#2和#3的项,但您的投影分句(即{"items.$":1})只是要求返回数组中的第一个元素.

那么,您可以做些什么来确保#2和#3匹配同一个子文档呢?您可以使用$elemMatch.通过这种方式,您还可以在投影分句中使用位置运算符$.

db.collection.find({
  "user_id": ObjectId("661137f22a31832ceb92ddbc"),
  "items": {
    "$elemMatch": {
      "product_id": ObjectId("662214f8cc5306f999369e99"),
      "size": ObjectId("660d444d0d7716ee24129675")
    }
  }
},
{
  "items.$": 1
})

Mongo Playground


事实上,如果您发现自己最常在items级别工作,建议您将items条目"拉平"为以下各个文档.您可以通过索引获得更简单的查询和性能提升等好处.

{
    display_id: "38bd6126-02a1-47b9-b567-00aaf2eb076f",
    user_id: ObjectId("661137f22a31832ceb92ddbc"),
    product_id: ObjectId("662214f8cc5306f999369e99"),
    size: ObjectId("660d444d0d7716ee24129675"),
    qty: 2
}

Mongo Playground

Database相关问答推荐

Prisma - 将属性的类型设置为枚举数组

DynamoDB 扫描 - 具有相同分区键的项目按顺序返回

使用 Npgsql 执行年龄查询并在 .NET 应用程序中返回结果?

如何高效地存储 100 万个单词并通过starts_with、contains 或ends_with 进行查询?

无法向 SiriDB 添加新副本

如何使用错误消息中指定的 tbspaceid tableid 在 DB2 中查找表和列

在 SQL Server 2008 R2 中,如何强制一列对于整个表是唯一的?

Membase 和 Couchbase 有什么区别?

如何更改 SQLite 数据库列中的值?

Select 最佳主键 + 编号系统

如何在大型数据库中使用 typeahead.js

South migration error: NoMigrations exception for django.contrib.auth

连接字符串中超时

为 Java servlet 管理数据库连接的最佳方法

从 postgresql 转储文件填充 MySQL 数据库

Oracle:如何在 Oracle SQL 中将十六进制转换为十进制?

App=EntityFramework 在 Sql 连接字符串中有什么作用?

使用 Django 的复合/复合主/唯一键

Spring data : CrudRepository 的保存方法和更新

遍历数据库中的每条记录 - Ruby on Rails / ActiveRecord