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{}}}
Related
I try to write queries for mongodb collection in Golang. However to use db.Collection.find() method we need to add filter in an interface{} type. I can use bson.D and bson.M to create filters. However, The user will send as a string these filters to backend side. For example:
In Golang:
filter := `bson.D{ // a string variable sent by UI
{"$and",
bson.A{
bson.D{{"rating", bson.D{{"$gt", 7}}}},
bson.D{{"rating", bson.D{{"$lte", 10}}}},
},
},
}`
How can I convert dynamic string filter to interface{} type for accepting by find() method.
I think one workaround for parse query string could be the query string from UI could be raw json like {"$and": [{"rating": {"$gt": 7}}, {"rating": {"$lte", 10}]}, then you could parse it through bson.UnmarshalExtJSON
Sample codes
filterStr := `{"$and": [{"rating": {"$gt": 7}}, {"rating": {"$lte", 10}]}`
var filter interface{}
err := bson.UnmarshalExtJSON([]byte(filterStr), true, &filter)
// the filter could be passed to Find() method
I have a filter on MongoDB Compass filter Between two dates and an string of two posible values like this code:
{closed_at: {$gt: ISODate('2020-07-01T00:00:00.700+00:00'),$lt: ISODate('2020-07-30T00:00:00.700+00:00')}, status: { $in: ["paid", "delivered"] }}
(I expect the same 1256 Documents if filter the same values on Go)
Now I need to convert this filter to a valid bson.M expression, can´t find the trick for the "status" string filed, have this query expression but have an error message:
query := bson.M{
"status" : ["paid", "delivered"], //Error: Invalid array bound '"paid"', the value must be representable by 'int' type
"closed_at": bson.M{"$gt": from, "$lt": to},
}
cursor, err := client.Database("orders").Collection("orders").Find(ctx,query)
¿Which is the correct way to declare the status field and pass value query to Find method?
You didn't translate the query completely:
"status": bson.M{"$in":[]string{"paid","delivered"}}
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)
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)
I'm Using Mongo Go Adapter: github.com/mongodb/mongo-go-driver/
I'm trying different patterns but none of them working for me.
//ref struct
type userbase struct {
Name string `bosn:"Name"`
Coins int `bson:"Coins"`
}
//ref code, it's updating _id, but not updating a value
filter := bson.M{"name": "Dinamis"}
update := bson.D{{"$inc", bson.M{"Coins": 1}}}
db := Client.Database("Nothing").Collection("dataUser")
db.UpdateOne(context.Background(), filter, update)
//update filters that i also used
update := bson.D{{"$inc", bson.D{{"Coins", 1},}},}
//simple ways was tryed also
update := &userbase{name, amount} //should i try *userbase{} ?
//Also i'm tryed
ReplaceOne()
FindOneAndReplace()
FindOneAndUpdate()
it's hard to dig deeper b-cuz of luck of actual documentation: https://docs.mongodb.com/ecosystem/drivers/go/
Thanks #Wan Bachtiar for answering this in official MongoDB-go-adapter group.
By default queries in MongoDB is case sensitive on the field name. In
your struct you defined the field to be Name, but in your filter to
specify name. This would result in no documents matching the query
predicates for the the update operation. For example, if you have a
document as below:
{ "_id": ObjectId("..."), "Name": "Dinamis", "Coins": 1 }
You can perform an update to increment the number of Coins using below
snippet:
collection := client.Database("Nothing").Collection("dataUser")
filter := bson.M{"Name": "Dinamis"}
update := bson.D{{"$inc", bson.M{"Coins": 1}}}
result, err := collection.UpdateOne(context.TODO(), filter, update)
Also, note that you have a typo on the bson tag in your struct. It’s
supposed to be bson:"Name" not bosn:"Name". You may find Query
Documents as a useful reference (Select the Go tab to show examples in
Go)
Regards, Wan.