Golang MongoDB Driver sort - mongodb

How to query find using golang mongodb driver?
I try this one :
db.Collection("products").Find(nil, bson.M{}, &options.FindOptions{Sort: "-price"})
But I got this error :
cannot transform type string to a BSON Document: WriteString can only write while positioned on a Element or Value but is positioned on a TopLevel
I don't know what to pass to Sort variable becuase it is an interface{}.

try the below code
findOptions := options.Find()
// Sort by `price` field descending
findOptions.SetSort(bson.D{{"price", -1}})
db.Collection("products").Find(nil, bson.D{}, findOptions)

I couldn't pass ‍‍bson.D to options(It caused error).
but this code worked for me:
queryOptions := options.FindOneOptions{}
queryOptions.SetSort(bson.D{{"priority", -1}, {"last_error_time", 1}})
sResult := collection.FindOne(context.TODO(), queryFilter, &queryOptions)

A few notes I've come across trying to solve a related problem:
If trying to sort by multiple fields be sure to use bson.D rather
than bson.M because bson.M doesn't preserve order.
If trying to programmatically build up multiple sort fields, try
appending bson.E to a bson.D
As dassum did, pass bson.M{} for an empty filter as recommended by
the mongo documentation
Applied:
sort := bson.D{}
for _, example := examples {
sort = append(sort, bson.E{example, 1})
}
findOptions.SetSort(sort)
db.Collection("products").Find(nil, bson.D{}, findOptions)

Related

missing type in composite literal go AND missing key in map literal go

Im trying to do Pagination with MongoDB
I write this code:
findOptions := options.Find()
findOptions.SetLimit(20)
findOptions.SetSort(bson.M{{"_id", 1}})
cursor, err34 := collection.Find(context.Background(), bson.M{{"_id", bson.M{{"$gte", last_id}}}}, findOptions)
Now
It keeps complaining:
missing type in composite literal go AND missing key in map literal go
It complains for this part:
findOptions.SetSort(bson.M{{"_id", 1}})
and
bson.M{{"_id", bson.M{{"$gte", last_id}}}}, findOptions)
I'm stuck with this error since so many hours and its very frustrating.
Please Help :(
bson.M is a map:
type M map[string]interface{}
So use the map composite literal syntax to create a value of it:
bson.M{"_id": 1}
And:
bson.M{"_id": bson.M{"$gte": last_id}}

golang mongo-go-driver can't increment a previously nil value

I have this kind of query to run. Running this query manually return OK with upsertedCount = 1 when the key not exist
db.test.update({Key: 'random-id'}, {$inc: {Version: 1}},{upsert: true})
I try to convert it to mongodb golang version below
client, _ := mongo.Connect(context.TODO(), options.Client().ApplyURI("mongodb://localhost:27017/"))
coll := client.Database("test").Collection("test")
filter := bson.D{bson.E{"Key", "random-id"}}
docs := bson.D{bson.E{"$inc", bson.E{"Version", 1}}}
upsert := true
result, err := coll.UpdateOne(
context.TODO(),
filter, docs,
&options.UpdateOptions{Upsert: &upsert})
if err != nil {
panic(err)
}
fmt.Print(result)
Unfortunately, this query returns error
multiple write errors: [{write errors: [{Cannot increment with non-numeric argument: {key: "Version"}}]}, {<nil>}]
Why can't it works? It seems that the driver trying to increment it without sending it to mongo
Edit:
change the schema case to Upper, to follow the go code
Use simpler version of code
The problem is with your docs value. It's supposed to be a valid document. bson.D is a valid document if all its elements are valid. It has an element with $inc key, which requires its value to be a valid document too. bson.E is not a document, it's an element of a document.
Change your docs to this:
docs := bson.D{bson.E{"$inc", bson.D{bson.E{"Version", 1}}}}
And it will work.
If order is not important (it isn't in your case), alternatively you may use bson.M to model your filter and docs like this:
filter := bson.M{"Key": "random-id"}
docs := bson.M{
"$inc": bson.M{"Version": 1},
}
This is much simpler, clearer and more intuitive.
Also note that there are builders for the options. Obtain your options.UpdateOptions value safely, idiomatically and clearly like this:
options.Update().SetUpsert(true)

Query Mongo for empty object

I'm trying to query a mongo collection where a field is not an empty object. db.collection.find({Status: {$ne: {}}}) works from javascript, my question is how to translate the empty object representation to go/go's driver?
filter := bson.M{"Status": bson.M{"$ne": {}}} generates a composite literal type interface{} syntax error.
The answer (which became obvious as I was writing this question) is to add bson.M to my empty object:
filter := bson.M{"Status": bson.M{"$ne": bson.M{}}}

Update/Replace mongodb document using struct & mongodb/mongo-go-driver

I am trying to update/replace a mongodb document using a struct but i keep on getting err: update document must contain key beginning with '$'
collection := r.client.Database(database).Collection(greetingCollection)
payment.MongoID = objectid.New()
filter := bson.NewDocument(bson.EC.String("id", payment.ID))
_, err := collection.UpdateOne(ctx, filter, payment)
return err
I believe the accepted answer did not work for me because I am using the go.mongodb.org/mongo-driver package. With this package, the syntax is even simpler:
update := bson.M{
"$set": yourDocument,
}
collection.UpdateOne(ctx, filter, update)
You should provide an update statement instead of a document as third parameter to the Collection.UpdateOne method. For example:
update := bson.NewDocument(
bson.EC.SubDocumentFromElements(
"$set",
bson.EC.Double("pi", 3.14159),
),
)
collection.UpdateOne(ctx, filter, update)
See more on the available update operators in the MongoDB docs (the keys begin with '$').

How to "sort" and "limit" results in mongodb?

I'm trying to execute a query with "sort" and "limit". With mgo you could do Find(nil).Sort(“-when”).Limit(10) but the new, official mongo driver has no such methods. How can I sort and "limit" with the new driver?
In the current version mongo-go-driver v1.0.3, the options are simplified. For example to perform find, sort and limit:
import (
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
options := options.Find()
// Sort by `_id` field descending
options.SetSort(bson.D{{"_id", -1}})
// Limit by 10 documents only
options.SetLimit(10)
cursor, err := collection.Find(context.Background(), bson.D{}, options)
See more available options on godoc.org/go.mongodb.org/mongo-driver/mongo/options. Especially FindOptions for all possible options for Find().
The official driver is not straightforward as mgo. You can do sort and limit using the findopt.Limit and findopt.Sort.
You can see examples from the official repository.
https://github.com/mongodb/mongo-go-driver/blob/5fea1444e52844a15513c0d9490327b2bd89ed7c/mongo/crud_spec_test.go#L364
You can use
findOptions := options.Find()
findOptions.SetLimit(2)
findOptions.SetSkip(2)
...
cursor, err := collection.Find(context.Background(), bson.M{}, findOptions)
resource at https://www.mongodb.com/blog/post/mongodb-go-driver-tutorial
you need import "github.com/mongodb/mongo-go-driver/options" package to build a findOptions.
import github.com/mongodb/mongo-go-driver/options
findOptions := options.Find() // build a `findOptions`
findOptions.SetSort(map[string]int{"when": -1}) // reverse order by `when`
findOptions.SetSkip(0) // skip whatever you want, like `offset` clause in mysql
findOptions.SetLimit(10) // like `limit` clause in mysql
// apply findOptions
cur, err := collection.Find(context.TODO(), bson.D{}, findOptions)
// resolve err
for cur.Next(context.TODO()) {
// call cur.Decode()
}
The sort-option apparently requires you to add a map[string]interface{} where you can specify a field as key and a sortOrder as value (where 1 means ascending and -1 means descending) as following:
sortMap := make(map[string]interface{})
sortMap["version"] = 1
opt := findopt.Sort(sortMap)
As far as I can see this means that you are only able to properly sort results by one sortField because keys in a go map are stored in a random order.
ONE LINE OPTION
I know there is already a lot of answers but you can do it as one line (if you need it for any case of yours)
// From the Doc
// func (f *FindOptions) SetSort(sort interface{}) *FindOptions
cursor, err := collection.Find(context.Background(), bson.M{}, options.Find().SetSort(map[string]int{"when": -1}).SetLimit(10))
SetSort() and the others currently returns the parent pointer itself