How to get the distinct value of a collection - mongodb

I am trying the use of mongodb and Go and I cannot get the distinct values of the field in a collection.
This is my code:
import (
"context"
"fmt"
"log"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type House struct {
Ciudad string
}
func main() {
client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
log.Fatal(err)
}
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
err = client.Connect(ctx)
collection := client.Database("test").Collection("houses")
var house repository.House
fmt.Println(collection.Distinct(ctx, "City", &house))
}
After execute this always I am geting an empty array. Any idea that is wrong in this code?

Replace the line
fmt.Println(collection.Distinct(ctx, "City", &house))
With
fmt.Println(collection.Distinct(ctx, "City", bson.D{{}}))
The third parameter, filter, is a BSON document, https://godoc.org/go.mongodb.org/mongo-driver/mongo#Collection.Distinct. Note that Distinct() returns two values, ([]interface, error).

Related

How to list collections in mongodb

In golang..
I get list mongodb database name below..
filter := bson.D{{}}
dbs, _ := client.ListDatabaseNames(context.TODO(), filter)
fmt.Printf("%+v\n", dbs)
But, I want to get list collections name.
How about ListCollectionNames?
Here's an example from the documentation. I added some placeholder lines that you need to replace by your client connection code and getting a database:
package main
import (
"context"
"fmt"
"log"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
func main() {
// Placeholder:
//
// Connect to MongoDB, handle error
client, err := mongo.connect(....)
if err != nil {
log.Fatal(err)
}
// Obtain the DB, by name. db will have the type
// *mongo.Database
db := client.Database("name-of-your-DB")
// use a filter to only select capped collections
result, err := db.ListCollectionNames(
context.TODO(),
bson.D{{"options.capped", true}})
if err != nil {
log.Fatal(err)
}
for _, coll := range result {
fmt.Println(coll)
}
}

List MongoDB databases names using regex [duplicate]

Question
How can I list databases only with the given prefix (prefix_)?
Example:
package main
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"log"
)
type foo struct {
Value string
}
func main() {
clientOptions := options.Client().ApplyURI("mongodb://10.0.12.76:27018")
client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatal(err)
}
db := [3]string{"prefix_foo", "prefix_bar", "bar"}
for _, element := range db {
_, err := client.Database(element).Collection("placeholder").InsertOne(context.TODO(), foo{"sth"})
if err != nil {
log.Fatal(err)
}
}
filter := bson.D{{}}
dbs, err := client.ListDatabaseNames(context.TODO(), filter)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", dbs)
}
Output:
[admin bar config local prefix_bar prefix_foo]
Expected output:
[prefix_bar prefix_foo]
Bonus:
It is possible to create a database without defining new struct in my case foo?
My goal is to run a query on databases only with a prefix, so maybe better solution exists than listing dbs and then run a query on each database?
Simply filter by the name property, which denotes the database name. And to list databases starting with a given prefix, you may use a regexp being ^prefix_:
filter := bson.M{"name": primitive.Regex{Pattern: "^prefix_"}}
Other filter options are listed on the listDatabases command page:
You can specify a condition on any of the fields in the output of listDatabases:
name
sizeOnDisk
empty
shards
And you may use an empty bson.M{} to insert an empty document (_id will be added of course).

MongoDB list databases with given prefix in Go

Question
How can I list databases only with the given prefix (prefix_)?
Example:
package main
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"log"
)
type foo struct {
Value string
}
func main() {
clientOptions := options.Client().ApplyURI("mongodb://10.0.12.76:27018")
client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatal(err)
}
db := [3]string{"prefix_foo", "prefix_bar", "bar"}
for _, element := range db {
_, err := client.Database(element).Collection("placeholder").InsertOne(context.TODO(), foo{"sth"})
if err != nil {
log.Fatal(err)
}
}
filter := bson.D{{}}
dbs, err := client.ListDatabaseNames(context.TODO(), filter)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", dbs)
}
Output:
[admin bar config local prefix_bar prefix_foo]
Expected output:
[prefix_bar prefix_foo]
Bonus:
It is possible to create a database without defining new struct in my case foo?
My goal is to run a query on databases only with a prefix, so maybe better solution exists than listing dbs and then run a query on each database?
Simply filter by the name property, which denotes the database name. And to list databases starting with a given prefix, you may use a regexp being ^prefix_:
filter := bson.M{"name": primitive.Regex{Pattern: "^prefix_"}}
Other filter options are listed on the listDatabases command page:
You can specify a condition on any of the fields in the output of listDatabases:
name
sizeOnDisk
empty
shards
And you may use an empty bson.M{} to insert an empty document (_id will be added of course).

Find entries via substring regex query in mongodb-go-driver

I can't get the official go mongo driver to successfully return objects that are queried via a regex query.
I already know how to do it via the mongo shell and get my expected results.
With this example i get all entries that contain "he" in their 'text' field:
db.getCollection('test').find({"text": /he/})
same with this one:
db.getCollection('test').find({"text": {$regex: /he/, $options: ''}})
This is my current code that doesn't work:
package main
import (
"context"
"fmt"
"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 main() {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
defer cancel()
client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
fmt.Println(err)
return
}
err = client.Connect(ctx)
if err != nil {
fmt.Println(err)
return
}
db := client.Database("test")
coll := db.Collection("test")
filter := bson.D{{"text", primitive.Regex{Pattern: "/he/", Options: ""}}}
ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cur, err := coll.Find(ctx, filter)
if err != nil {
fmt.Println(err)
return
}
i := 0
for cur.Next(ctx) {
i = i + 1
}
fmt.Println("Found", i, "elements")
}
Per example in the official mongo-go-driver repository, this should work.
My current entries in the collection just contain 2 fields, the id field and an extra text field. I currently have 3 entries. that look like this:
{
"_id" : ObjectId("5c9cc7e9950198ceeefecbdd"),
"text" : "hello world"
},
{
"_id" : ObjectId("5c9cc7f6950198ceeefecbec"),
"text" : "hello"
},
{
"_id" : ObjectId("5c9cc804950198ceeefecbfa"),
"text" : "test world"
}
My expected results with the code from above, should be the first 2 entries. Instead i get an empty cursor back.
Does anybode know, what i am doing wrong?
Thanks for your help.
primitive.Regex struct accepts Pattern value without slashes, so it must be:
filter := bson.D{{"text", primitive.Regex{Pattern: "he", Options: ""}}}
Try this one
. -> matches any character
*-> matches zero of more occurrence of previous character
So below filter will give you all results which has "he" as substring
filter = bson.M{"text": primitive.Regex{Pattern: ".*" + "he" + ".*", Options: "i"}}

Golang mongodb mgo driver Upsert / UpsertId documentation

The mongodb documentation says:
The fields and values of both the and parameters if the parameter contains only update operator expressions. The update creates a base document from the equality clauses in the parameter, and then applies the update expressions from the parameter.
And the mgo documentation says:
Upsert finds a single document matching the provided selector document and modifies it according to the update document. If no document matching the selector is found, the update document is applied to the selector document and the result is inserted in the collection.
But if i do an upsert like this:
session.UpsertId(data.Code, data)
I end up with an entry which have an ObjectID generated automatically by mongodb, instead of data.Code.
this means that UpsertId expect data to be formated with update operators and you can't use a an arbitrary struct? Or what i'm missing here?
Pd. Mongo 2.4.9 mgo v2 golang go version devel +f613443bb13a
EDIT:
This is a sample of what i mean, using the sample code from Neil Lunn:
package main
import (
"fmt"
"gopkg.in/mgo.v2"
// "gopkg.in/mgo.v2/bson"
)
type Person struct {
Code string
Name string
}
func main() {
session, err := mgo.Dial("admin:admin#localhost");
if err != nil {
fmt.Println("Error: ", err)
return
// panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("test").C("people")
var p = Person{
Code: "1234",
Name: "Bill",
}
_, err = c.UpsertId( p.Code, &p )
result := Person{}
err = c.FindId(p.Code).One(&result)
if err != nil {
fmt.Println("FindId Error: ", err)
return
// panic(err)
}
fmt.Println("Person", result)
}
I found the documentation of the MongoDB was right. The correct way to do this is to wrap the struct to insert into an update operator.
The sample code provided by Neil Lunn, would look like:
package main
import (
"fmt"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type Person struct {
Code string
Name string
}
func main() {
session, err := mgo.Dial("admin:admin#localhost");
if err != nil {
fmt.Println("Error: ", err)
return
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("test").C("people")
var p = Person{
Code: "1234",
Name: "Bill",
}
upsertdata := bson.M{ "$set": p}
info , err2 := c.UpsertId( p.Code, upsertdata )
fmt.Println("UpsertId -> ", info, err2)
result := Person{}
err = c.FindId(p.Code).One(&result)
if err != nil {
fmt.Println("FindId Error: ", err)
return
}
fmt.Println("Person", result)
}
Thank you very much for your interest and help Neil.
You seem to be talking about assigning a struct with a custom _id field here. This really comes down to how you define your struct. Here is a quick example:
package main
import (
"fmt"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type Person struct {
ID string `bson:"_id"`
Name string
}
func main() {
session, err := mgo.Dial("127.0.0.1");
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("test").C("people")
var p = Person{
ID: "1",
Name: "Bill",
}
_, err = c.UpsertId( p.ID, &p )
result := Person{}
err = c.Find(bson.M{"_id": p.ID}).One(&result)
if err != nil {
panic(err)
}
fmt.Println("Person", result)
}
So in the custom definition here I am mapping the ID field to bson _id and defining it's type as string. As shown in the example this is exactly what happens when serialized via UpsertId and then retrieved.
Now you have elaborated I'll point to the difference on the struct definition.
What I have produces this:
{ "_id": 1, "name": "Bill" }
What you have ( without the same mapping on the struct ) does this:
{ "_id": ObjectId("53cfa557e248860d16e1f7e0"), "code": 1, "name": "Bill" }
As you see, the _id given in the upsert will never match because none of your fields in the struct are mapped to _id. You need the same as I have:
type Person struct {
Code string `bson:"_id"`
Name string
}
That maps a field to the mandatory _id field, otherwise one is automatically produced for you.