Table of Contents
Kyte is a MongoDB query builder for Golang. It is designed to be simple and easy to use. Kyte's most unique feature is its ability to build MongoDB queries using a struct schema. This allows you to build queries using a struct that represents the schema of your MongoDB collection that prevents you from making mistakes in your queries check Advanced Usage for more details.
Currently, it supports Filter operations only. Aggregate and Update operations will be added in the future.
Kyte is built with a straightforward vision: Make it easy. As any Gopher would know, working with MongoDB in Golang can be a bit of a hassle because of bson
and primitive
packages. Kyte aims to simplify the process of building MongoDB queries in Golang by providing a simple and easy-to-use API. It also provides a way to build queries using a struct schema, which is unique to Kyte.
go get github.com/aaydin-tr/kyte
Following is a simple example of how to use Kyte to build a MongoDB query.
query, err := kyte.Filter().
Equal("name", "John").
GreaterThan("age", 20).
Build()
The above code will generate the following MongoDB query:
{ "name": {"$eq": "John"}, "age": {"$gt": 20 } }
Kyte allows you to build queries using a struct schema. This is useful when you want to prevent mistakes in your queries. For example, if you have a struct that represents the schema of your MongoDB collection, you can use it to build queries. Kyte will ensure that the fields you use in your queries are valid and exist in the schema. For this purpose Kyte provides two option functions: Source
and ValidateField
.
Source
function is used to specify the struct schema that you want to use to build queries.
ValidateField
function is used to validate the fields that you use in your queries. ( By default, it is enabled. )
Note: You can also use
ValidateField(false)
to disable field validation.
type User struct {
Name string `bson:"name"`
Age int `bson:"age"`
}
var user User
query, err := kyte.Filter(kyte.Source(&user)).
Equal(&user.Name, "John").
GreaterThan(&user.Age, 20).
Build()
When you use kyte.Source
function, you can pass a pointer of the struct field of your schema to the query builder functions. This will ensure that the fields you use in your queries are valid and exist in the schema.
Note: You can also use
string
value as a field name and Kyte still will validate the field. But using a pointer to the struct field is recommended.
Kyte supports global filters that are automatically applied to all filter instances. This is particularly useful for scenarios like multi-tenancy where certain conditions should always be included in your queries.
// Set up global filters
kyte.AddGlobalFilter(kyte.Filter().Equal("tenantId", "123"))
kyte.AddGlobalFilter(kyte.Filter().Equal("isActive", true))
// Create a new filter - global filters will be automatically included
query, err := kyte.Filter().
Equal("name", "John").
Build()
// The resulting query will include both the global filters and your specific conditions:
// { "tenantId": {"$eq": "123"}, "isActive": {"$eq": true}, "name": {"$eq": "John"} }
// If you need to ignore global filters for a specific query:
query, err := kyte.Filter(kyte.IgnoreGlobalFilters()).
Equal("name", "John").
Build()
// The resulting query will not include global filters:
// { "name": {"$eq": "John"} }
You can manage global filters using these functions:
// Add a global filter
kyte.AddGlobalFilter(kyte.Filter().Equal("tenantId", "123"))
// Get all current global filters
globalFilters := kyte.GetGlobalFilters()
// Clear all global filters
kyte.ClearGlobalFilters()
Global filters are thread-safe and can be used in concurrent applications. They are particularly useful for:
- Multi-tenancy: Automatically adding tenant ID to all queries
- Soft Delete: Always excluding deleted records
- Access Control: Adding user permission filters
- Data Partitioning: Filtering by organization or department
- Equal ($eq)
Equal("name", "John") // { "name": {"$eq": "John"} }
- NotEqual ($ne)
NotEqual("name", "John") // { "name": {"$ne": "John"} }
- GreaterThan ($gt)
GreaterThan("age", 20) // { "age": {"$gt": 20} }
- GreaterThanOrEqual ($gte)
GreaterThanOrEqual("age", 20) // { "age": {"$gte": 20} }
- LessThan ($lt)
LessThan("age", 20) // { "age": {"$lt": 20} }
- LessThanOrEqual ($lte)
LessThanOrEqual("age", 20) // { "age": {"$lte": 20} }
- In ($in)
In("name", []string{"John", "Doe"}) // { "name": {"$in": ["John", "Doe"]} }
- NotIn ($nin)
NotIn("name", []string{"John", "Doe"}) // { "name": {"$nin": ["John", "Doe"]} }
- And ($and)
And( Filter(). Equal("name", "John"). GreaterThan("age", 20), ) // { "$and": [ { "name": {"$eq": "John"} }, { "age": {"$gt": 20} } ] }
- Or ($or)
Or( Filter(). Equal("name", "John"). GreaterThan("age", 20), ) // { "$or": [ { "name": {"$eq": "John"} }, { "age": {"$gt": 20} } ] }
- Nor ($nor)
Nor( Filter(). Equal("name", "John"). GreaterThan("age", 20), ) // { "$nor": [ { "name": {"$eq": "John"} }, { "age": {"$gt": 20} } ] }
- Regex ($regex)
Regex("name", regexp.MustCompile("John"), "i") // { "name": {"$regex": "John", "$options": "i"} }
- Exists ($exists)
Exists("name", true) // { "name": {"$exists": true} }
- Type ($type)
Type("name", bsontype.String) // { "name": {"$type": "string"} }
- Mod ($mod )
Mod("age", 2, 0) // { "age": {"$mod": [2, 0]} }
- Where ($where)
Where("this.name.length > 10") // { "$where": "this.name.length > 10" }
- All ($all )
All("name", []string{"John", "Doe"}) // { "name": {"$all": ["John", "Doe"]} }
- Size ($size )
Size("name", 10) // { "name": {"$size": 10} }
- JsonSchema ($jsonSchema )
JsonSchema(bson.M{"required": []string{"name"}}) // { "$jsonSchema": {"required": ["name"]} }
- Raw
Raw(bson.D{{"name", "John"}}) // { "name": "John" }
- ToJSON (Converts the filter to a JSON string can be used for debugging)
jsonQuery, _ := kyte.Filter(). Equal("name", "John"). GreaterThan("age", 20). ToJSON() fmt.Println(jsonQuery) // { "name": {"$eq": "John"}, "age": {"$gt": 20} }