You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何查询MongoDB数组内对象?查询返回空数组问题求助

问题描述

现有MongoDB的messages集合文档结构如下:

{
    "_id" : ObjectId("64caa6599b2ec8d2da9e8e58"),
    "message" : {
        "text" : "hey"
    },
    "users" : [
        {
            "from" : "64c7acfbe872c97c7912ca09",
            "to" : "64c2d5612172d620ac18714f"
        }
    ],
    "sender" : ObjectId("64c7acfbe872c97c7912ca09"),
    "createdAt" : ISODate("2023-08-02T18:54:17.176+0000"),
    "updatedAt" : ISODate("2023-08-02T18:54:17.176+0000"),
    "__v" : NumberInt(0)
}

想要查询包含指定from和to的users数组的文档,试了两种写法都返回空数组:

const messages = await messageModel.find({
// first try
    users: {
      $all: [from, to],
    },
// second try 
    // users: {
    //   $elemMatch: {
    //     from: from,
    //     to: to,
    //   }
   
})
.sort({ updatedAt: 1 })
console.log("messages=>" ,JSON.stringify(messages))

对应的Mongoose MessageModel定义如下:

const mongoose = require("mongoose");

const messageSchema = mongoose.Schema(
  {
    message: {
      text: {
        type: String,
        required: true,
      },
    },
    users: Array,
    sender: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
},
  {
    timestamps: true,
  }
);

module.exports = mongoose.model("messages", messageSchema);

疑问:users字段定义为Array类型是不是不能用$elemMatch?怎么才能正确查到目标文档?

解决方案

之前查询失败的原因

  1. $all写法的问题:$all是用来匹配数组包含所有指定元素的文档,但你传的from和to是字符串ID,而users数组里的元素是对象,类型完全不匹配,肯定查不到。
  2. $elemMatch写法的问题:users定义成Array类型是可以用$elemMatch的,你的问题一是代码没写完(缺了闭合括号),二是可能存在类型不匹配——文档里的from/to是字符串,但你传入的变量是ObjectId类型,或者反过来,导致匹配失败。

正确的查询方法

方法一:修正$elemMatch查询

先确保from和to的类型和文档里的一致(文档里是字符串就传字符串,是ObjectId就转成对应类型),然后补全语法:

const messages = await messageModel.find({
  users: {
    $elemMatch: {
      from: from,
      to: to
    }
  }
})
.sort({ updatedAt: 1 });

方法二:直接嵌套字段查询(不用$elemMatch)

如果只是匹配数组中单个对象的多个字段,MongoDB支持直接写嵌套路径,写法更简洁:

const messages = await messageModel.find({
  "users.from": from,
  "users.to": to
})
.sort({ updatedAt: 1 });

长期优化:完善Schema定义

为了彻底避免类型匹配问题,建议把users数组的结构明确写在Schema里,这样Mongoose会自动处理类型转换,还能做字段校验:

const messageSchema = mongoose.Schema(
  {
    message: {
      text: {
        type: String,
        required: true,
      },
    },
    users: [{
      from: {
        type: mongoose.Schema.Types.ObjectId,
        ref: "User"
      },
      to: {
        type: mongoose.Schema.Types.ObjectId,
        ref: "User"
      }
    }],
    sender: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
  },
  {
    timestamps: true,
  }
);

这样定义后,不管你传的是字符串ID还是ObjectId,Mongoose都会自动转换成对应类型,不用再手动处理类型问题。

内容的提问来源于stack exchange,提问作者siimransiingh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 16:14:55