mongoDB $sort 不一致的结果

huangapple go评论146阅读模式
英文:

mongoDB $sort inconsistent results

问题

我在go语言中有以下查询,运行良好:

query["name"] = bson.M{"$regex": searchStr, "$options": "i"}
query["likes"] = userSession.Id
c.Find(query).Skip(0).Limit(2).Select(bson.M{"name":1, "profile":1, "description":1, "user_id":1, "likes":1}).Sort("-pro", "-check").All(&business)

然后我尝试使用聚合框架编写相同的查询:

query["name"] = bson.M{"$regex": searchStr, "$options": "i"}
query["likes"] = userSession.Id
oe := bson.M{
    "$match" :query,
}
oa := bson.M{
    "$project": bson.M {"pro": 1, "check": 1, "name":1, "profile":1, "description":1, "user_id":1, "likes":1, "nrLikes": bson.M{ "$size": "$likes" }, "city": 1, "country": 1, "industry": 1},
}
ol := bson.M{
    "$limit" :pageSize,
}
os := bson.M{
    "$skip" :skips,
}
or := bson.M{
    "$sort" : bson.M {"pro": -1, "check": -1},
}

pipe := c.Pipe([]bson.M{oe, oa, or, os, ol  })

pipe.All(&business)

第二个查询大部分时间都能正常工作,但有10%的时间会返回不同顺序的结果。

有什么想法吗?

稍后编辑:以下是结果:

[]bson.M{
{
    "description": "<p>sasdfdasf</p>",
    "profile":     []interface {}{
        "rKwMmXPWheGczwvGn2TzSRU7jRorhorKwMmXPWheGczwvGn2TzSRU7jRorho=0.jpg",
    },
    "likes": []interface {}{
        "Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9",
    },
    "nrLikes":  int(1),
    "name":     "ediloc.com2",
    "city":     "Calimanesti",
    "industry": "Automotive",
    "_id":      "Yo\xd4f\x1a\xa9Q|w\tG^",
    "user_id":  "Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9",
    "country":  "Romania",
},
{
    "_id":         "Yo\xc7\xd7\x1a\xa9Qy1[&#39;\xea",
    "user_id":     "Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9",
    "name":        "ediloc.com",
    "country":     "Romania",
    "description": "<p>a</p>",
    "profile":     []interface {}{
        "1ssSySNRZwGJJwqzXghL6qzAVfWZis1ssSySNRZwGJJwqzXghL6qzAVfWZis=1.jpg",
    },
    "likes": []interface {}{
        "Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9",
    },
    "nrLikes":  int(1),
    "city":     "Calimanesti",
    "industry": "Accounting",
},
}


[]bson.M{
{
    "likes": []interface {}{
        "Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9",
    },
    "_id":     "Yo\xd4f\x1a\xa9Q|w\tG^",
    "name":    "ediloc.com2",
    "city":    "Calimanesti",
    "country": "Romania",
    "profile": []interface {}{
        "rKwMmXPWheGczwvGn2TzSRU7jRorhorKwMmXPWheGczwvGn2TzSRU7jRorho=0.jpg",
    },
    "user_id":     "Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9",
    "industry":    "Automotive",
    "nrLikes":     int(1),
},
{
    "_id":      "Yo\xc7\xd7\x1a\xa9Qy1[&#39;\xea",
    "user_id":  "Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9",
    "industry": "Accounting",
    "profile":  []interface {}{
        "1ssSySNRZwGJJwqzXghL6qzAVfWZis1ssSySNRZwGJJwqzXghL6qzAVfWZis=1.jpg",
    },
    "likes": []interface {}{
        "Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9",
    },
    "nrLikes":     int(1),
    "name":        "ediloc.com",
    "city":        "Calimanesti",
    "country":     "Romania",
    "description": "<p>a</p>",
},
}


[]bson.M{
{
    "nrLikes":     int(1),
    "user_id":     "Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9",
    "description": "<p>a</p>",
    "profile":     []interface {}{
        "1ssSySNRZwGJJwqzXghL6qzAVfWZis1ssSySNRZwGJJwqzXghL6qzAVfWZis=1.jpg",
    },
    "country":  "Romania",
    "industry": "Accounting",
    "likes":    []interface {}{
        "Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9",
    },
    "_id":  "Yo\xc7\xd7\x1a\xa9Qy1[&#39;\xea",
    "name": "ediloc.com",
    "city": "Calimanesti",
},
{
    "name":        "ediloc.com2",
    "industry":    "Automotive",
    "description": "<p>sasdfdasf</p>",
    "likes":       []interface {}{
        "Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9",
    },
    "user_id": "Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9",
    "city":    "Calimanesti",
    "country": "Romania",
    "profile": []interface {}{
        "rKwMmXPWheGczwvGn2TzSRU7jRorhorKwMmXPWheGczwvGn2TzSRU7jRorho=0.jpg",
    },
    "nrLikes": int(1),
    "_id":     "Yo\xd4f\x1a\xa9Q|w\tG^",
},
}

pro和check字段是int32类型具有较高pro字段编号的文档应优先于具有较高check字段的文档

<details>
<summary>英文:</summary>

I have the following query in go lang which works fine:

    query[&quot;name&quot;] = bson.M{&quot;$regex&quot;: searchStr, &quot;$options&quot;: &quot;i&quot;}
    query[&quot;likes&quot;] = userSession.Id
    c.Find(query).Skip(0).Limit(2).Select(bson.M{&quot;name&quot;:1, &quot;profile&quot;:1, &quot;description&quot;:1, &quot;user_id&quot;:1, &quot;likes&quot;:1}).Sort(&quot;-pro&quot;, &quot;-check&quot;).All(&amp;business);

Then I tried to write the same query using the aggregation framework:

    query[&quot;name&quot;] = bson.M{&quot;$regex&quot;: searchStr, &quot;$options&quot;: &quot;i&quot;}
    query[&quot;likes&quot;] = userSession.Id
    oe := bson.M{
        &quot;$match&quot; :query,
	}
	oa := bson.M{
        &quot;$project&quot;: bson.M {&quot;pro&quot;: 1, &quot;check&quot;: 1, &quot;name&quot;:1, &quot;profile&quot;:1, &quot;description&quot;:1, &quot;user_id&quot;:1, &quot;likes&quot;:1, &quot;nrLikes&quot;: bson.M{ &quot;$size&quot;: &quot;$likes&quot; }, &quot;city&quot;: 1, &quot;country&quot;: 1, &quot;industry&quot;: 1},
	}
	ol := bson.M{
        &quot;$limit&quot; :pageSize,
	}
	os := bson.M{
        &quot;$skip&quot; :skips,
	}
	or := bson.M{
        &quot;$sort&quot; : bson.M {&quot;pro&quot;: -1, &quot;check&quot;: -1},
	}

    pipe := c.Pipe([]bson.M{oe, oa, or, os, ol  })
	
	pipe.All(&amp;business)


The second query works fine 90% of the time, but 10% of the times it returns a different order for results. 

Any thoughts?

Later edit: Here are the resuls

    []bson.M{
    {
        &quot;description&quot;: &quot;&lt;p&gt;sasdfdasf&lt;/p&gt;&quot;,
        &quot;profile&quot;:     []interface {}{
            &quot;rKwMmXPWheGczwvGn2TzSRU7jRorhorKwMmXPWheGczwvGn2TzSRU7jRorho=0.jpg&quot;,
        },
        &quot;likes&quot;: []interface {}{
            &quot;Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9&quot;,
        },
        &quot;nrLikes&quot;:  int(1),
        &quot;name&quot;:     &quot;ediloc.com2&quot;,
        &quot;city&quot;:     &quot;Calimanesti&quot;,
        &quot;industry&quot;: &quot;Automotive&quot;,
        &quot;_id&quot;:      &quot;Yo\xd4f\x1a\xa9Q|w\tG^&quot;,
        &quot;user_id&quot;:  &quot;Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9&quot;,
        &quot;country&quot;:  &quot;Romania&quot;,
    },
    {
        &quot;_id&quot;:         &quot;Yo\xc7\xd7\x1a\xa9Qy1[&#39;\xea&quot;,
        &quot;user_id&quot;:     &quot;Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9&quot;,
        &quot;name&quot;:        &quot;ediloc.com&quot;,
        &quot;country&quot;:     &quot;Romania&quot;,
        &quot;description&quot;: &quot;&lt;p&gt;a&lt;/p&gt;&quot;,
        &quot;profile&quot;:     []interface {}{
            &quot;1ssSySNRZwGJJwqzXghL6qzAVfWZis1ssSySNRZwGJJwqzXghL6qzAVfWZis=1.jpg&quot;,
        },
        &quot;likes&quot;: []interface {}{
            &quot;Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9&quot;,
        },
        &quot;nrLikes&quot;:  int(1),
        &quot;city&quot;:     &quot;Calimanesti&quot;,
        &quot;industry&quot;: &quot;Accounting&quot;,
    },
    }


    []bson.M{
    {
        &quot;likes&quot;: []interface {}{
            &quot;Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9&quot;,
        },
        &quot;_id&quot;:     &quot;Yo\xd4f\x1a\xa9Q|w\tG^&quot;,
        &quot;name&quot;:    &quot;ediloc.com2&quot;,
        &quot;city&quot;:    &quot;Calimanesti&quot;,
        &quot;country&quot;: &quot;Romania&quot;,
        &quot;profile&quot;: []interface {}{
            &quot;rKwMmXPWheGczwvGn2TzSRU7jRorhorKwMmXPWheGczwvGn2TzSRU7jRorho=0.jpg&quot;,
        },
        &quot;user_id&quot;:     &quot;Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9&quot;,
        &quot;industry&quot;:    &quot;Automotive&quot;,,
        &quot;nrLikes&quot;:     int(1),
    },
    {
        &quot;_id&quot;:      &quot;Yo\xc7\xd7\x1a\xa9Qy1[&#39;\xea&quot;,
        &quot;user_id&quot;:  &quot;Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9&quot;,
        &quot;industry&quot;: &quot;Accounting&quot;,
        &quot;profile&quot;:  []interface {}{
            &quot;1ssSySNRZwGJJwqzXghL6qzAVfWZis1ssSySNRZwGJJwqzXghL6qzAVfWZis=1.jpg&quot;,
        },
        &quot;likes&quot;: []interface {}{
            &quot;Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9&quot;,
        },
        &quot;nrLikes&quot;:     int(1),
        &quot;name&quot;:        &quot;ediloc.com&quot;,
        &quot;city&quot;:        &quot;Calimanesti&quot;,
        &quot;country&quot;:     &quot;Romania&quot;,
        &quot;description&quot;: &quot;&lt;p&gt;a&lt;/p&gt;&quot;,
    },
    }


    []bson.M{
    {
        &quot;nrLikes&quot;:     int(1),
        &quot;user_id&quot;:     &quot;Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9&quot;,
        &quot;description&quot;: &quot;&lt;p&gt;a&lt;/p&gt;&quot;,
        &quot;profile&quot;:     []interface {}{
            &quot;1ssSySNRZwGJJwqzXghL6qzAVfWZis1ssSySNRZwGJJwqzXghL6qzAVfWZis=1.jpg&quot;,
        },
        &quot;country&quot;:  &quot;Romania&quot;,
        &quot;industry&quot;: &quot;Accounting&quot;,
        &quot;likes&quot;:    []interface {}{
            &quot;Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9&quot;,
        },
        &quot;_id&quot;:  &quot;Yo\xc7\xd7\x1a\xa9Qy1[&#39;\xea&quot;,
        &quot;name&quot;: &quot;ediloc.com&quot;,
        &quot;city&quot;: &quot;Calimanesti&quot;,
    },
    {
        &quot;name&quot;:        &quot;ediloc.com2&quot;,
        &quot;industry&quot;:    &quot;Automotive&quot;,
        &quot;description&quot;: &quot;&lt;p&gt;sasdfdasf&lt;/p&gt;&quot;,
        &quot;likes&quot;:       []interface {}{
            &quot;Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9&quot;,
        },
        &quot;user_id&quot;: &quot;Yo\xc7;\x1a\xa9Qy\b\xb8\xa2\xf9&quot;,
        &quot;city&quot;:    &quot;Calimanesti&quot;,
        &quot;country&quot;: &quot;Romania&quot;,
        &quot;profile&quot;: []interface {}{
            &quot;rKwMmXPWheGczwvGn2TzSRU7jRorhorKwMmXPWheGczwvGn2TzSRU7jRorho=0.jpg&quot;,
        },
        &quot;nrLikes&quot;: int(1),
        &quot;_id&quot;:     &quot;Yo\xd4f\x1a\xa9Q|w\tG^&quot;,
    },
    }

Pro and check fields are in32, the documents with higher pro field number should have priority over the documents that have higher check fields.


</details>


# 答案1
**得分**: 2

确保在限制和跳过阶段之前设置排序管道阶段只有在排序输入上才能可靠地获得相同的结果

**编辑**

意识到您正在使用`bson.M {&quot;pro&quot;: -1, &quot;check&quot;: -1}`来定义排序顺序在Go中映射的迭代顺序是未指定的可能会发生变化这可能是您得到不一致结果的原因

尝试将其更改为`bson.D`以便保持按列排序的顺序

可以查看查询[Sort](http://bazaar.launchpad.net/+branch/mgo/v2/view/head:/session.go#L2130)方法如何从提供的字符串构建它。

对于您的用例您可以将`or`变量更改为

    or := bson.M{
        &quot;$sort&quot;: bson.D{
	    	bson.DocElem{Name: &quot;pro&quot;, Value: -1},
		    bson.DocElem{Name: &quot;check&quot;, Value: -1},
         },
	}

<details>
<summary>英文:</summary>

Make sure you have your sort pipeline stage *before* your limit &amp; skip stages. You can only reliably obtain the same results with limit/skip on sorted input. 

**EDIT**

Realised that you are using `bson.M {&quot;pro&quot;: -1, &quot;check&quot;: -1}` to define your sort order. The iteration order of a map is unspecified in Go and can change. Hence this is probably why you are getting inconsistent results.

Try changing this to a `bson.D` so that the order of columns to sort by is maintained.

It make help to see how the query [Sort](http://bazaar.launchpad.net/+branch/mgo/v2/view/head:/session.go#L2130) method constructs this from the strings you provide.

For your use case, you would change the `or` variable to:

    or := bson.M{
        &quot;$sort&quot;: bson.D{
	    	bson.DocElem{Name: &quot;pro&quot;, Value: -1},
		    bson.DocElem{Name: &quot;check&quot;, Value: -1},
         },
	}

</details>



huangapple
  • 本文由 发表于 2017年7月26日 07:08:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/45314871.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定