MongoDB切片数组投影返回其他字段

67up9zun  于 2023-03-29  发布在  Go
关注(0)|答案(2)|浏览(140)

在我的数据中,其中一个字段是一个数组,我只想返回该数组的一部分,仅此而已,没有更多的字段。但是当我在投影中使用$slice时,它将返回所有的字段。
我的数据:

{
  "_id": {
    "$oid": "641eca0f5687d0937c1041e2"
  },
  "email": "example@gmail.com",
  "password": "$2b$10$MBuDAi3k7jTvckTsqQliQeWeg18JebLaDdltzMJwJ92bwP7i84Ee2",
  "emailVerified": true,
  "transactions": [
    {
      "category": "t2",
      "subCategory": "bread",
      "type": "expense",
      "date": "2023-03-25T16:53:59.779Z",
      "amount": "1000",
      "id": {
        "$oid": "641f2727dc59db57eac9fa29"
      }
    },
    {
      "category": "t3",
      "subCategory": "bread",
      "type": "expense",
      "date": "2023-03-25T16:54:04.243Z",
      "amount": "1000",
      "id": {
        "$oid": "641f272cdc59db57eac9fa2a"
      }
    },
    {
      "category": "t4",
      "subCategory": "bread",
      "type": "expense",
      "date": "2023-03-25T16:54:08.780Z",
      "amount": "1000",
      "id": {
        "$oid": "641f2730dc59db57eac9fa2b"
      }
    }
  ]
}

我在node.js中的查询是这样的:

const result = await users.findOne(
  { _id: new ObjectId(id) },
  { projection: { transactions: { $slice: [1, 2] } }}
);

通过这个投影,我得到了结果中的所有字段。如果我将投影更改为{ transactions: { $slice: [1, 2] }, _id: 1 },它将只返回transactions_id。但我只想要交易。

更新日期:

经过一番研究,我发现这对于aggregate方法是可能的。聚合所做的基本上是基于管道上的前一阶段重新创建投影。但我仍然不知道projection on findOne方法。

const aggCursor = users.aggregate<TransactionsPagRes>([
  {
    $match: { _id: new ObjectId(id) },
  },
  {
    $project: {
      _id: 0,
      transactions: { $slice: ['$transactions', 1, 2] },
    },
  },
]);

const result = await aggCursor.next();
bnl4lu3b

bnl4lu3b1#

如果你不介意返回transactions,你需要像这样把其他你不需要的属性列入黑名单:

db.collection.find({},
{
  transactions: {
    $slice: [
      1,
      2
    ]
  },
  _id: 0,
  email: 0,
  password: 0,
  emailVerified: 0
})

它将返回如下信息:

[
  {
    "transactions": [
      {
        "amount": "1000",
        "category": "t3",
        "date": "2023-03-25T16:54:04.243Z",
        "id": ObjectId("641f272cdc59db57eac9fa2a"),
        "subCategory": "bread",
        "type": "expense"
      },
      {
        "amount": "1000",
        "category": "t4",
        "date": "2023-03-25T16:54:08.780Z",
        "id": ObjectId("641f2730dc59db57eac9fa2b"),
        "subCategory": "bread",
        "type": "expense"
      }
    ]
  }
]

如果你想拥有一个用户事务的平面数组,$unwind聚合是一种方法:

db.collection.aggregate([
  {
    $match: {
      _id: "641eca0f5687d0937c1041e2"
    },
    
  },
  {
    "$project": {
      transactions: {
        $slice: [
          "$transactions",
          1,
          2
        ]
      }
    }
  },
  {
    "$unwind": "$transactions"
  }
])

退货:

[
  {
    "_id": "641eca0f5687d0937c1041e2",
    "transactions": {
      "amount": "1000",
      "category": "t3",
      "date": "2023-03-25T16:54:04.243Z",
      "id": ObjectId("641f272cdc59db57eac9fa2a"),
      "subCategory": "bread",
      "type": "expense"
    }
  },
  {
    "_id": "641eca0f5687d0937c1041e2",
    "transactions": {
      "amount": "1000",
      "category": "t4",
      "date": "2023-03-25T16:54:08.780Z",
      "id": ObjectId("641f2730dc59db57eac9fa2b"),
      "subCategory": "bread",
      "type": "expense"
    }
  }
]

MongoDB Playground .

hfsqlsce

hfsqlsce2#

使用$slice操作符似乎并不像投影那样排除其他字段,这似乎是MongoDB中的意外行为。
有几个选择可以获得您想要的行为:
1.修改传递给查找的投影
由于投影永远不会隐式地排除_id,因此无论如何都需要修改它。要排除所有其他字段,要么显式地排除每个字段,要么包含实际不存在的字段。

const result = await users.findOne(
  { _id: new ObjectId(id) },
  { projection: { 
     _id:0,
     _not_a_real_field: 1,
     transactions: { $slice: [1, 2] } 
  }}
);

Playground
1.使用聚合管道您仍然需要显式排除_id,但不需要引用不存在的字段来排除其他字段

[
  {$match: {_id: ObjectId("641eca0f5687d0937c1041e2")}}},
  {$project: {
      _id: 0,
      transactions: {$slice: ["$transactions",1,2]}
  }}
]

Playground

相关问题