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

Go语言MongoDB API开发:嵌套时间戳对比、指定字段查询及Token更新方案咨询

Go操作MongoDB的三个问题解决方案

针对你用Go开发MongoDB API遇到的这三个问题,结合你的文档结构,我给你具体的实现方案:

1. 按_id和tokens.owner查询,仅返回匹配的token和created_at

要实现这个需求,我们可以利用MongoDB的**投影(Projection)**和数组位置操作符$,它会返回数组中第一个匹配条件的元素。在Go中使用mongo-go-driver的代码示例如下:

import (
    "context"
    "time"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

func getMatchingToken(collection *mongo.Collection, docID string, owner string) (map[string]interface{}, error) {
    // 转换_id为ObjectID类型
    objID, err := primitive.ObjectIDFromHex(docID)
    if err != nil {
        return nil, err
    }

    // 构造查询条件:匹配文档_id和tokens数组中owner字段
    filter := bson.M{
        "_id": objID,
        "tokens.owner": owner,
    }

    // 投影:只返回匹配的token和created_at,不返回_id
    projection := bson.M{
        "tokens.$.token": 1,
        "tokens.$.created_at": 1,
        "_id": 0,
    }

    var result bson.M
    err = collection.FindOne(context.TODO(), filter, options.FindOne().SetProjection(projection)).Decode(&result)
    if err != nil {
        return nil, err
    }

    return result, nil
}

说明:

  • tokens.$中的$会定位到tokens数组中第一个匹配tokens.owner的元素
  • 投影里明确指定只返回该元素的token和created_at字段,排除了其他无关内容

2. 判断updated_at是否大于匹配的tokens.created_at,返回对应结果

需求是:如果文档的updated_at大于匹配的tokens.owner对应的created_at,则返回false,否则返回true。我们可以通过聚合管道来实现这个逻辑,先过滤文档,再展开数组并比较时间:

func checkTimestampCondition(collection *mongo.Collection, docID string, owner string) (bool, error) {
    objID, err := primitive.ObjectIDFromHex(docID)
    if err != nil {
        return false, err
    }

    // 聚合管道:先匹配文档,再展开tokens数组,过滤目标owner,最后比较时间
    pipeline := []bson.M{
        {"$match": bson.M{
            "_id": objID,
            "tokens.owner": owner,
        }},
        {"$unwind": "$tokens"}, // 展开tokens数组为单个文档
        {"$match": bson.M{"tokens.owner": owner}}, // 过滤出目标owner的token记录
        {"$project": bson.M{
            // 判断updated_at是否大于tokens.created_at,结果存入shouldReturnFalse
            "shouldReturnFalse": bson.M{"$gt": []interface{}{"$updated_at", "$tokens.created_at"}},
            "_id": 0,
        }},
    }

    cursor, err := collection.Aggregate(context.TODO(), pipeline)
    if err != nil {
        return false, err
    }
    defer cursor.Close(context.TODO())

    var result struct {
        ShouldReturnFalse bool `bson:"shouldReturnFalse"`
    }

    if cursor.Next(context.TODO()) {
        err := cursor.Decode(&result)
        if err != nil {
            return false, err
        }
        // 按需求返回:若updated_at>created_at,返回false;否则返回true
        return !result.ShouldReturnFalse, nil
    }

    // 未找到匹配的记录,可根据业务逻辑返回默认值
    return false, mongo.ErrNoDocuments
}

说明:

  • 聚合管道先定位到目标文档,再展开数组确保我们能单独处理匹配的token记录
  • $gt操作符用于比较两个时间戳,最终根据比较结果返回符合需求的布尔值

3. 更新指定tokens.owner的token,而非追加新元素

要直接更新数组中匹配条件的元素,我们可以使用$set操作符结合数组位置操作符$(更新第一个匹配元素),或者数组过滤器arrayFilters(更新所有匹配元素)。

方案一:更新第一个匹配的token元素

func updateMatchingToken(collection *mongo.Collection, docID string, owner string, newToken string) (*mongo.UpdateResult, error) {
    objID, err := primitive.ObjectIDFromHex(docID)
    if err != nil {
        return nil, err
    }

    filter := bson.M{
        "_id": objID,
        "tokens.owner": owner,
    }

    // 使用$set更新匹配的token元素,同时更新updated_at
    update := bson.M{
        "$set": bson.M{
            "tokens.$.token": newToken,
            "updated_at": time.Now().UTC(),
        },
    }

    result, err := collection.UpdateOne(context.TODO(), filter, update)
    return result, err
}

方案二:更新所有匹配的token元素(如果有多个相同owner的记录)

如果你的文档中可能存在多个tokens.owner相同的元素,可以使用数组过滤器来批量更新:

func updateAllMatchingTokens(collection *mongo.Collection, docID string, owner string, newToken string) (*mongo.UpdateResult, error) {
    objID, err := primitive.ObjectIDFromHex(docID)
    if err != nil {
        return nil, err
    }

    filter := bson.M{
        "_id": objID,
    }

    update := bson.M{
        "$set": bson.M{
            "tokens.$[elem].token": newToken,
            "updated_at": time.Now().UTC(),
        },
    }

    // 设置数组过滤器:匹配所有owner为指定值的元素
    opts := options.Update().SetArrayFilters(options.ArrayFilters{
        Filters: []interface{}{
            bson.M{"elem.owner": owner},
        },
    })

    result, err := collection.UpdateOne(context.TODO(), filter, update, opts)
    return result, err
}

说明:

  • tokens.$.token中的$会定位到第一个匹配tokens.owner的元素
  • 数组过滤器$[elem]可以匹配所有符合条件的元素,适合批量更新场景
  • 同时更新updated_at字段,符合文档的时间戳维护逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 14:23:13