mikejs / gomongo

Go driver for MongoDB

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

col.Find with regexp /foo/ fails

hokapoka opened this issue · comments

I'd like to query using mongo's regexp search, for example :

db.mycollection.find( { name:/foo/ } )

Where it will match any documents whose "name" property contains "foo"

I have tried to use:

q := map[string]string{
  "name":"/foo/",
}

But it will only match on name that exatcly match the string "/foo/",
as you would expect.

So I tried to use go lang's regexp package for example :

===================================

package main


import (
   mongo "github.com/mikejs/gomongo/mongo"
   "regexp"
)

func main(){

   conn, _ := mongo.Connect("127.0.0.1")
   db := conn.GetDB("test")
   col := db.GetCollection("mycollection")


   q, _ := mongo.Marshal(map[string]interface{}{
       "name":regexp.MustCompile("/foo/"),
   })

   col.FindOne(q)

}

But it panics at runtime, I've attached the output at the bottom.

I wasn't sure if I should be using the regexp Package or some other
type to pass. I've looked through the tests and can't see regexp
used.

Have you got any suggestions.

panic: runtime error: invalid memory address or nil pointer dereference                                                                            

panic PC=0x7f5624538d50
runtime.panic+0xa7 /home/andrew/go/src/pkg/runtime/proc.c:1065
    runtime.panic(0x49408c, 0x7f562457c680)
runtime.panicstring+0x69 /home/andrew/go/src/pkg/runtime/runtime.c:83
    runtime.panicstring(0x5c0a5f, 0x2200000004)
runtime.sigpanic+0x144 /home/andrew/go/src/pkg/runtime/linux/thread.c:286
    runtime.sigpanic()
github%2ecom/mikejs/gomongo/mongo.*opQuery·Bytes+0x1d9 /home/andrew/go/src/pkg/github.com/mikejs/gomongo/mongo/message.go:179
    github%2ecom/mikejs/gomongo/mongo.*opQuery·Bytes(0x7f5624556870, 0x200000008, 0x7f5624538f18, 0x7f5624538f08)
github%2ecom/mikejs/gomongo/mongo.*Connection·sendMessageToReply+0x38 /home/andrew/go/src/pkg/github.com/mikejs/gomongo/mongo/collection.go:49
    github%2ecom/mikejs/gomongo/mongo.*Connection·sendMessageToReply(0x7f562457c580, 0x7f56245568a0, 0x7f5624556870, 0x7f560383065c, 0x7f5624556870
github%2ecom/mikejs/gomongo/mongo.*Collection·Query+0x104 /home/andrew/go/src/pkg/github.com/mikejs/gomongo/mongo/collection.go:104
    github%2ecom/mikejs/gomongo/mongo.*Collection·Query(0x7f5624558540, 0x0, 0x0, 0x100000000, 0x7f5624538ff0, ...)
github%2ecom/mikejs/gomongo/mongo.*Collection·FindOne+0x50 /home/andrew/go/src/pkg/github.com/mikejs/gomongo/mongo/collection.go:124
    github%2ecom/mikejs/gomongo/mongo.*Collection·FindOne(0x7f5624558540, 0x0, 0x0, 0x0, 0x7f5624556420, ...)
main.main+0x166 /home/andrew/testgomonog/main.go:59
    main.main()
runtime.mainstart+0xf /home/andrew/go/src/pkg/runtime/amd64/asm.s:77
    runtime.mainstart()
runtime.goexit /home/andrew/go/src/pkg/runtime/proc.c:148
    runtime.goexit()

goroutine 2 [3]:
runtime.entersyscall+0x28 /home/andrew/go/src/pkg/runtime/proc.c:572
    runtime.entersyscall()
syscall.Syscall6+0x5 /home/andrew/go/src/pkg/syscall/asm_linux_amd64.s:40
    syscall.Syscall6()
syscall.EpollWait+0x8d /home/andrew/go/src/pkg/syscall/zsyscall_linux_amd64.go:188
    syscall.EpollWait(0x7f5600000006, 0x7f562457c4b0, 0x100000001, 0xffffffff, 0xc, ...)
net.*pollster·WaitFD+0xfe /home/andrew/go/src/pkg/net/fd_linux.go:116
    net.*pollster·WaitFD(0x7f562457c3a0, 0x0, 0x0, 0x0, 0x0, ...)
net.*pollServer·Run+0xa3 /home/andrew/go/src/pkg/net/fd.go:207
    net.*pollServer·Run(0x7f562454c780, 0x0)
runtime.goexit /home/andrew/go/src/pkg/runtime/proc.c:148
    runtime.goexit()


I'#ve found a solution that gets me going, although I'm not sure is the best solution as mongo must be having to eval(uate) at runtime :

   q, _ := mongo.Marshal(map[string]interface{}{
       "$where":"/foo/.test(this.name)",
   })

Anyone else got a better solution?

commented

Hi hokapoka

In gomongo there is a code responsible for processing regexp. But probably the author has forgotten to add support in Marshal () sub. This small patch partially solves a problem, but I ask to notice - without support of "options".

diff --git a/mongo/bson-struct.go b/mongo/bson-struct.go
index b01cb2b..a7dd70b 100644
--- a/mongo/bson-struct.go
+++ b/mongo/bson-struct.go
@@ -16,6 +16,7 @@ import (
        "time"
        "container/vector"
        "strconv"
+       "regexp"
 )
 
 type structBuilder struct {
@@ -289,6 +290,8 @@ func Marshal(val interface{}) (BSON, os.Error) {
                return &_Long{int64(v), _Null{}}, nil
        case *time.Time:
                return &_Date{v, _Null{}}, nil
+       case *regexp.Regexp:
+               return &_Regex{v.String(), "", _Null{}}, nil
        }
 
        var value reflect.Value

Work example

dmitrys@laptop:~/tmp$ mongo
MongoDB shell version: 1.6.6-pre-
connecting to: test
> db.products.find()
{ "_id" : ObjectId("4d4805cf59235ebab2f68173"), "name" : "HTC A8181 Desire", "price" : 578 }
{ "_id" : ObjectId("4d4805df59235ebab2f68174"), "name" : "HTC A3333 Wildfire", "price" : 341 }
{ "_id" : ObjectId("4d48060859235ebab2f68175"), "name" : "HTC A6363 Legend", "price" : 579 }
{ "_id" : ObjectId("4d48062959235ebab2f68176"), "name" : "HTC T3333 Touch2", "price" : 285 }
{ "_id" : ObjectId("4d4806a859235ebab2f68177"), "name" : "HTC B3333 NotExisting", "price" : 1 }

> exit
bye
dmitrys@laptop:~/tmp$ 
dmitrys@laptop:~/tmp$ cat main.go 
package main

import (
                "os"
                "fmt"
                "regexp"
                "github.com/mikejs/gomongo/mongo"
)

func main() {
        var dbc *mongo.Connection
        var err os.Error
        var query mongo.BSON
        var cursor *mongo.Cursor

        mmap := make(map[string]interface{})
        mmap["name"] = regexp.MustCompile("(T|A)3333")

        query ,err = mongo.Marshal(mmap)

        if err != nil {
                fmt.Println(err)
                return
        }

        if dbc, err = mongo.Connect("localhost"); err != nil {
                fmt.Println(err)
                return
        }

        collection := dbc.GetDB("test").GetCollection("products")

        if cursor, err = collection.Query(query,0,0); err != nil {
                fmt.Println(err)
                return
        }

        for {

                if !cursor.HasMore() {
                        break
                }

                data, _ := cursor.GetNext()

                //fmt.Printf("Dump: %#v\n",data)
                fmt.Printf("Name: %s\n",data.Get("name").String())
                fmt.Printf("Price: %f\n\n",data.Get("price").Number())

        }
}
dmitrys@laptop:~/tmp$ 
dmitrys@laptop:~/tmp$ 8g main.go && 8l main.8 && ./8.out 
Name: HTC A3333 Wildfire
Price: 341.000000

Name: HTC T3333 Touch2
Price: 285.000000

dmitrys@laptop:~/tmp$ 

Hey deletus

That's great, at least in cases where there's no need to use options I can use the golang regexp.

I know there still some work to be done on the golang regexp package, maybe it'll be easier to add options when this happens.

Many thanks.

dagmark

That's the reason I open this issue, if you read the first message you'll see it panics if you use regexp.

I hadn't seen that implementation of a the go-mongo drive before. Thanks for links to it I'll install it later today and if I can use it as a drop-in replacement for this driver.

Thanks.

dagmark - I always hit the wrong button.