Skip to content

aaydin-tr/kyte

Repository files navigation


kyte

MongoDB Query Builder for Golang



Table of Contents
  1. About The Project
  2. Motivation
  3. Installation
  4. Usage
  5. Advanced Usage
  6. Supported Operators


About The Project

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.

Motivation

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.

Installation

go get github.com/aaydin-tr/kyte

Usage

Basic Usage

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 } }

Advanced Usage

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.

Global Filters

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

Supported Operators

  • 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} }