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

MongoDB报错Cannot apply $pull to a non-array value求助

问题分析与解决方案

报错根源

  1. "Cannot apply $pull to a non-array value":集合中部分文档的liked/disliked字段并非数组类型(比如是单个ObjectID、字符串等非数组值),你原本用的$ifNull仅能处理字段为null的情况,无法覆盖其他非数组场景。
  2. "error decoding key disliked: cannot decode document into []primitive.ObjectID":查询解码时,文档中disliked字段的实际类型与模型定义的[]primitive.ObjectID不匹配,导致解码失败。

修复步骤

1. 合并更新操作并完善类型校验

将两次UpdateOne合并为一次,用$cond判断字段是否为数组,确保无论当前字段是什么类型,都转为数组后再执行$addToSet和$pull:

func (f *ForumServiceImpl) LikedAPost(postId string, userId string) (*model.Forum, int64, error) {
    postObjectId, err := primitive.ObjectIDFromHex(postId)
    if err != nil {
        return nil, 0, err
    }

    userObjectId, err := primitive.ObjectIDFromHex(userId)
    if err != nil {
        return nil, 0, err
    }

    filter := bson.M{"_id": postObjectId}

    // 合并确保数组类型和更新操作
    update := bson.M{
        // 先确保liked是数组:如果是数组则保留,否则转为空数组
        "$set": bson.M{
            "liked": bson.M{
                "$cond": []interface{}{
                    bson.M{"$isArray": "$liked"},
                    "$liked",
                    primitive.A{},
                },
            },
            "disliked": bson.M{
                "$cond": []interface{}{
                    bson.M{"$isArray": "$disliked"},
                    "$disliked",
                    primitive.A{},
                },
            },
        },
        // 执行点赞和取消踩的操作
        "$addToSet": bson.M{"liked": userObjectId},
        "$pull":     bson.M{"disliked": userObjectId},
    }

    result, err := f.forumCollection.UpdateOne(context.TODO(), filter, update)
    if err != nil {
        return nil, 0, err
    }

    // 查询更新后的文档
    var forum model.Forum
    err = f.forumCollection.FindOne(context.TODO(), filter).Decode(&forum)
    if err != nil {
        return nil, 0, err
    }

    return &forum, result.ModifiedCount, nil
}

2. 批量修正现有脏数据

执行MongoDB命令,批量将集合中所有文档的liked/disliked字段转为数组类型(如果不是数组的话):

db.forums.updateMany(
    { $or: [
        { liked: { $not: { $type: "array" } } },
        { disliked: { $not: { $type: "array" } } }
    ] },
    [
        { $set: {
            liked: { $cond: [{ $isArray: "$liked" }, "$liked", []] },
            disliked: { $cond: [{ $isArray: "$disliked" }, "$disliked", []] }
        } }
    ]
)

3. 确保创建文档时字段初始化正确

模型中的default:"[]"标签仅在使用部分ORM(如GORM)创建文档且未赋值时生效,直接用MongoDB驱动插入时需要手动初始化:

// 创建新Forum文档时,显式初始化liked和disliked为空数组
newForum := model.Forum{
    // 其他字段赋值...
    Liked:    []primitive.ObjectID{},
    Disliked: []primitive.ObjectID{},
}
// 执行插入操作
_, err := f.forumCollection.InsertOne(context.TODO(), newForum)

关键说明

  • 用$isArray替代$ifNull,能覆盖所有非数组类型的字段(包括单个值、字符串等),彻底解决$pull的非数组报错。
  • 合并更新操作避免了两次数据库请求的并发问题,也提升了性能。
  • 批量修正脏数据是一次性操作,确保现有所有文档的字段类型符合模型定义,消除解码报错。

内容的提问来源于stack exchange,提问作者Gbenga B Ayannuga

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 15:07:35