【问题标题】:Mongodb use slice and elementmatchMongoDB使用切片和元素匹配
【发布时间】:2016-12-28 00:17:45
【问题描述】:

我正在尝试在 mongo db 中检索数组中的元素。我想检索与模式不匹配的前 15 个元素

假设我有

{
"_id" : ObjectId("s4dcsd5s4d6c54s6d"),
"items" : [
    {
        type : "TYPE_1",
        text : "blablabla"
    },
    {
        type : "TYPE_2",
        text : "blablabla"
    },
    {
        type : "TYPE_3",
        text : "blablabla"
    },
    {
        type : "TYPE_1",
        text : "blablabla"
    },
    {
        type : "TYPE_2",
        text : "blablabla"
    },
    {
        type : "TYPE_1",
        text : "blablabla"
    }
]
}

因此,与不匹配的元素相比,目前我要匹配的元素更多,这就是我使用 nin 的原因。但这是为了简化

如果我使用

db.history.find({ "_id" : ObjectId("s4dcsd5s4d6c54s6d")}, { "items" : { "$elemMatch" : { "type" : { "$nin" : [ "TYPE_2" , "TYPE_3"]}}}, "items" : { $slice : [0, 2]}}).pretty()

似乎没有考虑元素匹配(如果我将元素匹配放在切片之后,也是相反的)

如果我这样做:

db.history.find({ "_id" : ObjectId("s4dcsd5s4d6c54s6d")}, { "items" : { "$elemMatch" : { "type" : { "$nin" : [ "TYPE_2" , "TYPE_3"]}}, $slice : [0, 2]}}).pretty()

mongo 抛出错误

你知道我该怎么做吗?

非常感谢

【问题讨论】:

    标签: mongodb


    【解决方案1】:

    您不能在您的情况下使用$elemMatch,因为它只会返回第一个元素。来自documentation

    $elemMatch $elemMatch 操作符限制 查询结果中的字段仅包含第一个元素 匹配 $elemMatch 条件。

    您可以进行聚合查询,该查询将执行以下操作:

    • 匹配你的_id
    • 展开您的 items 数组以使数组中的每个项目都有一条记录
    • 匹配类型$nin你的数组[ "TYPE_2" , "TYPE_3"]
    • 限制结果数

    查询是:

    db.history.aggregate([{
            $match: {
                _id: ObjectId("s4dcsd5s4d6c54s6d")
            }
        }, {
            $unwind: '$items'
        }, {
            $match: {
                'items.type': { '$nin': ["TYPE_2", "TYPE_3"] }
            }
        },
        { $limit: 2 }
    ])
    

    它给出了:

    { "_id" : "s4dcsd5s4d6c54s6d", "items" : { "type" : "TYPE_1", "text" : "blablabla" } }
    { "_id" : "s4dcsd5s4d6c54s6d", "items" : { "type" : "TYPE_1", "text" : "blablabla" } }
    

    【讨论】:

    • 谢谢你。
    • 快速提问你使用springdata mongodb吗? :) 事实上我正在尝试使用你所说的` Aggregation aggregation = newAggregation(match(Criteria.where('id').is(profileID)), unwind('items'), match(Criteria.where( 'items.type').nin(ignoreditemstype)), limit(3), skip(1)); ` 我得到了:{ "aggregate" : "__collection__" , "pipeline" : [ { "$match" : { "id" : "5856dcf347816870aab76137"}} , { "$unwind" : "$items"} , { "$match" : { "items.type" : { "$nin" : [ "TYPE_2" , "TYPE_3" , "TYPE_4" , "TYPE_5" , "TYPE_6"]}}} , { "$limit" : 3} , { "$skip" : 0}]} 你有什么想法吗?
    • 如果您使用 objectId 类型作为 _id 而不是 String 这可能是问题stackoverflow.com/questions/14346028/…
    • 从我在这个讨论中看到的,这与我的问题无关。因为他们试图做的操作是将字符串(例如对用户 ID 的引用)与有效用户中的 objectID 进行比较。我的 profileID 字段是对象中的 ID:@Id private String id; 所以我不明白:/
    • 您可以逐步检查结果以查看问题所在,首先仅匹配,然后匹配+展开等。
    【解决方案2】:

    您需要使用聚合来限制您所拥有的形式的数组。使用 $filter 应用条件和 $slice 来限制数组元素。

    db.history.aggregate([{
        $match: {
            _id: ObjectId("586309d6772c68234445f2a5")
        }
    }, {
        "$project": {
            "items": {
                "$slice": [{
                        "$filter": {
                            "input": "$items",
                            "as": "item",
                            "cond": {
                                "$and": [{
                                    $ne: ["$$item.type", "TYPE_2"]
                                }, {
                                    $ne: ["$$item.type", "TYPE_3"]
                                }]
                            }
                        }
                    },
                    2
                ]
            }
        }
    }])
    

    样本输出:

    { "_id" : ObjectId("586309d6772c68234445f2a5"), "items" : [ { "type" : "TYPE_1", "text" : "blablabla" }, { "type" : "TYPE_1", "text" : "blablabla" } ] }
    

    【讨论】:

      猜你喜欢
      • 2018-07-02
      • 2013-10-01
      • 2016-08-11
      • 1970-01-01
      • 2020-07-02
      • 1970-01-01
      • 1970-01-01
      • 2019-02-15
      • 2015-06-21
      相关资源
      最近更新 更多