Skip to content

UpsertQuery

interface UpsertQuery<T> : UpdateQuery<T> 

DSL for MongoDB operators that are used to update existing values, creating new documents if none exist (does not include aggregation operators).

This interface is a variant of UpdateQuery used in upsert operations. See UpdateQuery for more information.

If you can't find the operator you're searching for, visit the tracking issue.

Constructors

UpsertQuery

@LowLevelApi
fun <T> UpsertQuery(context: BsonContext, options: UpdateOptions<T>? = null): UpsertQuery<T>

Creates an empty UpsertQuery.

Properties

all

open val <E> Field<T, Collection<E>>.all: Field<T, E>

open val <E> KProperty1<T, Collection<E>>.all: Field<T, E>

The all positional operator: selects all elements of an array.

This operator is used to declare an update that applies to all items of an array.

Example

class User(
    val name: String,
    val pets: List<Pet>,
)

class Pet(
    val name: String,
    val age: Int,
)

users.updateMany {
    User::pets.all / Pet::age inc 1
}

External resources

context

The context used to generate this expression.

field

Converts a Kotlin property into a Field.

selected

open val <E> Field<T, Collection<E>>.selected: Field<T, E>

open val <E> KProperty1<T, Collection<E>>.selected: Field<T, E>

The positional operator: update an array item selected in the filter.

When we use any or anyValue in a filter to select an item, we can use this operator to update whichever item was selected.

Do not use this operator in an upsert.

Example

class User(
    val name: String,
    val pets: List<Pet>,
)

class Pet(
    val name: String,
    val age: Int,
)

users.updateMany(
    filter = {
        User::pets.any / Pet::name eq "Bobby"
    },
    update = {
        User::pets.selected / Pet::age inc 1
    }
)

This example finds all users who have a pet named "Bobby", and increases its age by 1. Note that if the users have other pets, they are not impacted.

External resources

Functions

accept

@LowLevelApi
@DangerousMongoApi
abstract override fun accept(node: BsonNode)

Adds a new node as a child of this one.

acceptAll

Adds any number of nodes into this one.

addEachToSet

open fun <V> Field<T, Collection<V>>.addEachToSet(values: Iterable<V>, type: KType)

infix inline fun <V> Field<T, Collection<V>>.addEachToSet(values: Iterable<V>)

infix inline fun <V> KProperty1<T, Collection<V>>.addEachToSet(values: Iterable<V>)

Adds multiple values at the end of the array, unless they are already present.

Each value in values is treated independently. It if it is already present in the array, nothing happens. If it is absent from the array, it is added at the end.

MongoDB detects equality if the two documents are exactly identical. All the fields must be the same in the same order.

This is a convenience function for calling addToSet multiple times.

Example

class User(
    val name: String,
    val age: Int,
    val tokens: List<String>,
)

collection.updateOne(
    filter = {
        User::name eq "Bob"
    },
    update = {
        User::tokens addEachToSet listOf("123456789", "789456123")
    }
)

This will add "123456789" and "789465123" to the user's tokens only if they aren't already present. If only one of them is present, the other is added.

External resources

addToSet

abstract fun <V> Field<T, Collection<V>>.addToSet(value: V, type: KType)

infix inline fun <V> Field<T, Collection<V>>.addToSet(value: V)

infix inline fun <V> KProperty1<T, Collection<V>>.addToSet(value: V)

Adds value at the end of the array, unless it is already present, in which case it does nothing.

MongoDB detects equality if the two documents are exactly identical. All the fields must be the same in the same order.

Example

class User(
    val name: String,
    val age: Int,
    val tokens: List<String>,
)

collection.updateOne(
    filter = {
        User::name eq "Bob"
    },
    update = {
        User::tokens addToSet "123456789"
    }
)

This will add "123456789" to the user's tokens only if it isn't already present.

External resources

bitAnd

abstract infix fun Field<T, Long>.bitAnd(mask: Long)

open infix fun KProperty1<T, Long>.bitAnd(mask: Long)

abstract infix fun Field<T, Int>.bitAnd(mask: Int)

open infix fun KProperty1<T, Int>.bitAnd(mask: Int)

Performs a bitwise AND operation on a field.

This operator should always be used with a field of type Int or Long.

Example

class Switch(
    val _id: Int,
    val expdata: Int,
)

switches.filter {
    Switch::_id eq 1
}.updateOne {
    Switch::expdata bitAnd 10
}

External resources

bitOr

abstract infix fun Field<T, Long>.bitOr(mask: Long)

open infix fun KProperty1<T, Long>.bitOr(mask: Long)

abstract infix fun Field<T, Int>.bitOr(mask: Int)

open infix fun KProperty1<T, Int>.bitOr(mask: Int)

Performs a bitwise OR operation on a field.

This operator should always be used with a field of type Int or Long.

Example

class Switch(
    val _id: Int,
    val expdata: Int,
)

switches.filter {
    Switch::_id eq 1
}.updateOne {
    Switch::expdata bitOr 10
}

External resources

bitXor

abstract infix fun Field<T, Long>.bitXor(mask: Long)

open infix fun KProperty1<T, Long>.bitXor(mask: Long)

abstract infix fun Field<T, Int>.bitXor(mask: Int)

open infix fun KProperty1<T, Int>.bitXor(mask: Int)

Performs a bitwise XOR (exclusive OR) operation on a field.

This operator should always be used with a field of type Int or Long.

Example

class Switch(
    val _id: Int,
    val expdata: Int,
)

switches.filter {
    Switch::_id eq 1
}.updateOne {
    Switch::expdata bitXor 10
}

External resources

div

open operator fun <Root, Parent, Child> KProperty1<Root, Parent>.div(child: KProperty1<Parent & Any, Child>): Field<Root, Child>

Refers to child as a nested field of the current field.

open operator fun <Root, Type, Child> Field<Root, Type>.div(child: KProperty1<in Type & Any, Child>): Field<Root, Child>

Refers to child as a nested field of the current field.

open operator fun <Root, Type, Child> Field<Root, Type>.div(child: Field<Type, Child>): Field<Root, Child>

Refers to child as a nested field of the current field.

filter

@LowLevelApi
abstract fun <V> Field<T, Collection<V>>.filter(id: String): Field<T, V>

Filters an array and performs the specified update only on the filtered items.

Unlike selected, which only updates a single array element, filter can update multiple array elements. filter can also be nested.

Usage

MongoDB doesn't allow specifying the filter within the update itself, it must be specified in the options. The parameter id must match a declared array filter.

You may prefer using the overload which automatically registers the filter.

Example

class User(
    val name: String,
    val grades: List<Grade>,
)

class Grade(
    val subject: String,
    val grade: Int,
)

collection.updateOne(
    filter = {
        User::name eq "Bob"
    },
    options = {
        arrayFilter("maths") {
            Grade::subject eq "Maths"
        }
    },
    update = {
        User::grades.filter("maths") / Grade::grade inc 10
    }
)

This will increment all grades for the subject "Maths" for user "Bob".

External resources

abstract fun <V> Field<T, Collection<V>>.filter(id: String? = null, filter: ArrayFiltersOptionDsl<V>.(it: Field<ArrayFiltersOptionDsl.IteratorType<V>, V>) -> Unit): Field<T, V>

Filters an array and performs the specified update only on the filtered items.

Unlike selected, which only updates a single array element, filter can update multiple array elements. filter can also be nested.

This overload registers the array filter within the option automatically. There is no need to configure opensavvy.ktmongo.dsl.options.WithArrayFilters.arrayFilter.

Example

class User(
    val name: String,
    val grades: List<Grade>,
)

class Grade(
    val subject: String,
    val grade: Int,
)

collection.updateOne(
    filter = {
        User::name eq "Bob"
    },
    update = {
        User::grades.filter {
            it / Grade::subject eq "Maths"
        } / Grade::grade inc 10
    }
)

This will increment all grades for the subject "Maths" for user "Bob".

Operation priority

The operator priority rules in Kotlin mean that the following code:

User::grades / Grade::value.filter {  }

is interpreted as:

User::grades / (Grade::value.filter {  })

which is incorrect.

To avoid this, either use explicit parentheses:

(User::grades / Grade::value).filter {  }

Or use an intermediate variable:

val grades = User::grades / Grade::value
grades.filter {  }

External resources

Parameters

  • id: The identifier of the generated array filter. If null, a unique identifier is generated automatically.

  • filter: The filter expression to apply to the array element. The lambda passes a parameter that represents the current item during the iteration. The operators within this lambda are the same as FilterQuery.

freeze

@LowLevelApi
abstract override fun freeze()

Makes this expression immutable.

get

open operator fun <Root, Type> KProperty1<Root, Collection<Type>>.get(index: Int): Field<Root, Type>

Refers to a specific item in an array, by its index.

open operator fun <Root, Type> KProperty1<Root, Map<String, Type>>.get(index: String): Field<Root, Type>

Refers to a specific item in a map, by its name.

open operator fun <Root, Type> Field<Root, Collection<Type>>.get(index: Int): Field<Root, Type>

Refers to a specific item in an array, by its index.

open operator fun <Root, Type> Field<Root, Map<String, Type>>.get(key: String): Field<Root, Type>

Refers to a specific item in a map, by its name.

inc

abstract fun <V : Number> Field<T, V>.inc(amount: V, type: KType)

infix inline fun <V : Number> Field<T, V>.inc(amount: V)

infix inline fun <V : Number> KProperty1<T, V>.inc(amount: V)

Increments a field by the specified amount.

amount may be negative, in which case the field is decremented.

If the field doesn't exist (either the document doesn't have it, or the operation is an upsert and a new document is created), the field is created with an initial value of amount.

Use of this operator with a field with a null value will generate an error.

Example

class User(
    val name: String,
    val age: Int,
)

// It's the new year!
collection.updateMany {
    User::age inc 1
}

External resources

max

abstract fun <V : Comparable<V>> Field<T, V?>.max(value: V, type: KType)

infix inline fun <V : Comparable<V>> Field<T, V?>.max(value: V)

infix inline fun <V : Comparable<V>> KProperty1<T, V?>.max(value: V)

Updates the value of a field to the specified value only if the specified value is greater than the current value of the field.

If the field doesn't exist, the field is set to the specified value.

Example

class User(
    val name: String,
    val score: Int,
)

collection.updateMany {
    User::score max 100
}

External resources

min

abstract fun <V : Comparable<V>> Field<T, V?>.min(value: V, type: KType)

infix inline fun <V : Comparable<V>> Field<T, V?>.min(value: V)

infix inline fun <V : Comparable<V>> KProperty1<T, V?>.min(value: V)

Updates the value of a field to the specified value only if the specified value is less than the current value of the field.

If the field doesn't exist, the field is set to the specified value.

Example

class User(
    val name: String,
    val score: Int,
)

collection.updateMany {
    User::score min 10
}

External resources

mul

abstract fun <V : Number> Field<T, V>.mul(amount: V, type: KType)

infix inline fun <V : Number> Field<T, V>.mul(amount: V)

infix inline fun <V : Number> KProperty1<T, V>.mul(amount: V)

Multiplies a field by the specified amount.

If the field doesn't exist (either the document doesn't have it, or the operation is an upsert and a new document is created), the field is created with an initial value of 0.

Use of this operator with a field with a null value will generate an error.

Example

class User(
    val name: String,
    val price: Double,
)

collection.updateMany {
    User::price mul 2.0
}

External resources

plusAssign

inline operator fun <V : Number> Field<T, V>.plusAssign(amount: V)

inline operator fun <V : Number> KProperty1<T, V>.plusAssign(amount: V)

Increments a field by the specified amount.

amount may be negative, in which case the field is decremented.

If the field doesn't exist (either the document doesn't have it, or the operation is an upsert and a new document is created), the field is created with an initial value of amount.

Use of this operator with a field with a null value will generate an error.

Example

class User(
    val name: String,
    val age: Int,
)

// It's the new year!
collection.updateMany {
    User::age += 1
}

External resources

popFirst

abstract fun Field<T, Collection<*>>.popFirst()

open fun KProperty1<T, Collection<*>>.popFirst()

Removes the first element in the specified array.

Example

class User(
    val name: String,
    val age: Int,
    val scores: List<Int>,
)

collection.updateOne(
    fiilter = {
        User::name eq "Bob"
    },
    update = {
        User::scores.popFirst()
    }
)

External resources

popLast

abstract fun Field<T, Collection<*>>.popLast()

open fun KProperty1<T, Collection<*>>.popLast()

Removes the last element in the specified array.

Example

class User(
    val name: String,
    val age: Int,
    val scores: List<Int>,
)

collection.updateOne(
    fiilter = {
        User::name eq "Bob"
    },
    update = {
        User::scores.popLast()
    }
)

External resources

pull

abstract fun <V> Field<T, Collection<V>>.pull(value: V, type: KType)

infix inline fun <V> Field<T, Collection<V>>.pull(value: V)

infix inline fun <V> KProperty1<T, Collection<V>>.pull(value: V)

Removes all instances of value from the specified array.

Example

class User(
    val name: String,
    val tests: List<Int>,
)

users.updateOne(
    filter = { User::name eq "Paul" },
    update = {
        User::tests pull 10
    }
)

External resources

abstract fun <V> Field<T, Collection<V>>.pull(predicate: FilterQuery<V>.() -> Unit, type: KType)

infix inline fun <V> Field<T, Collection<V>>.pull(noinline predicate: FilterQuery<V>.() -> Unit)

infix inline fun <V> KProperty1<T, Collection<V>>.pull(noinline predicate: FilterQuery<V>.() -> Unit)

Removes all items of an array that match predicate.

To select items based on their own intrinsic value (e.g. whether the item is greater than some value), see pullValues.

Example

class User(
    val name: String,
    val tests: List<Grade>,
)

class Grade(
    val name: String,
    val score: Int,
)

users.updateOne(
    filter = { User::name eq "Paul" },
    update = {
        User::tests pull { Gradle::score lte 10 }
    }
)

External resources

pullValues

abstract fun <V> Field<T, Collection<V>>.pullValues(predicate: FilterQueryPredicate<V>.() -> Unit, type: KType)

infix inline fun <V> Field<T, Collection<V>>.pullValues(noinline predicate: FilterQueryPredicate<V>.() -> Unit)

infix inline fun <V> KProperty1<T, Collection<V>>.pullValues(noinline predicate: FilterQueryPredicate<V>.() -> Unit)

Removes all items of an array that match predicate.

To select items based on a value of one or multiple of their fields, see pull.

Example

class User(
    val name: String,
    val tests: List<Int>,
)

users.updateOne(
    filter = { User::name eq "Paul" },
    update = {
        User::tests pullValues { lte(10) }
    }
)

External resources

push

abstract fun <V> Field<T, Collection<V>>.push(value: V, type: KType)

infix inline fun <V> Field<T, Collection<V>>.push(value: V)

infix inline fun <V> KProperty1<T, Collection<V>>.push(value: V)

Adds value at the end of the array.

Unlike addToSet, this operator always adds the value, even if it's already present in the array.

Example

class User(
    val name: String,
    val age: Int,
    val scores: List<Int>,
)

collection.updateOne(
    filter = {
        User::name eq "Bob"
    },
    update = {
        User::scores push 100
    }
)

This will add 100 to the user's scores, even if it's already present.

External resources

abstract fun <V> Field<T, Collection<V>>.push(builder: UpdateQuery.PushBuilder<V>.() -> Unit, type: KType)

infix inline fun <V> Field<T, Collection<V>>.push(noinline builder: UpdateQuery.PushBuilder<V>.() -> Unit)

infix inline fun <V> KProperty1<T, Collection<V>>.push(noinline builder: UpdateQuery.PushBuilder<V>.() -> Unit)

Adds values to the end of the array with advanced options.

This method allows using MongoDB's advanced $push operators like $each and $slice.

Example

class User(
    val name: String,
    val age: Int,
    val tokens: List<String>,
)

collection.updateOne(
    filter = {
        User::name eq "Bob"
    },
    update = {
        User::tokens push {
            each("123", "456")
            slice(3)
        }
    }
)

This will add "123" and "456" to the user's tokens and keep only the last 3 elements.

External resources

pushEach

open fun <V> Field<T, Collection<V>>.pushEach(values: Iterable<V>, type: KType)

infix inline fun <V> Field<T, Collection<V>>.pushEach(values: Iterable<V>)

infix inline fun <V> KProperty1<T, Collection<V>>.pushEach(values: Iterable<V>)

Adds multiple values at the end of the array.

Unlike addToSet, this operator always adds all values, even if they're already present in the array.

This is a convenience function for calling push multiple times.

Example

class User(
    val name: String,
    val age: Int,
    val scores: List<Int>,
)

collection.updateOne(
    filter = {
        User::name eq "Bob"
    },
    update = {
        User::scores pushEach listOf(100, 200)
    }
)

This will add 100 and 200 to the user's scores, even if they're already present.

External resources

renameTo

abstract infix fun <V> Field<T, V>.renameTo(newName: Field<T, V>)

open infix fun <V> KProperty1<T, V>.renameTo(newName: Field<T, V>)

open infix fun <V> Field<T, V>.renameTo(newName: KProperty1<T, V>)

open infix fun <V> KProperty1<T, V>.renameTo(newName: KProperty1<T, V>)

Renames a field.

Example

class User(
    val name: String,
    val age: Int,
    val ageOld: Int,
)

collection.updateMany {
    User::ageOld renameTo User::age
}

External resources

set

abstract fun <V> Field<T, V>.set(value: V, type: KType)

infix inline fun <V> Field<T, V>.set(value: V)

infix inline fun <V> KProperty1<T, V>.set(value: V)

Replaces the value of a field with the specified value.

Example

class User(
    val name: String?,
    val age: Int,
)

collection.filter {
    User::name eq "foo"
}.updateMany {
    User::age set 18
}

External resources

See also

setIf

inline fun <V> Field<T, V>.setIf(condition: Boolean, value: V)

inline fun <V> KProperty1<T, V>.setIf(condition: Boolean, value: V)

Replaces the value of a field with the specified value, if condition is true.

If condition is false, this operator does nothing.

Example

class User(
    val name: String?,
    val age: Int,
)

collection.filter {
    User::name eq "foo"
}.updateMany {
    User::age.setIf(someComplexOperation, 18)
}

External resources

See also

setOnInsert

abstract fun <V> Field<T, V>.setOnInsert(value: V, type: KType)

infix inline fun <V> Field<T, V>.setOnInsert(value: V)

infix inline fun <V> KProperty1<T, V>.setOnInsert(value: V)

If an upsert operation results in an insert of a document, then this operator assigns the specified value to the field. If the update operation does not result in an insert, this operator does nothing.

Example

class User(
    val name: String?,
    val age: Int,
)

collection.filter {
    User::name eq "foo"
}.upsertOne {
    User::age setOnInsert 18
}

External resources

See also

  • set: Always set the value.

setToCurrentDate

Sets this field to the current date.

If the field does not exist, this operator adds the field to the document.

Example

class User(
    val name: String?,
    val age: Int,
    val modificationDate: Instant,
)

collection.filter {
    User::name eq "Bob"
}.updateMany {
    User::age set 18
    User::modificationDate.setToCurrentDate()
}

External resources

@JvmName(name = "setToCurrentTimestamp")
abstract fun Field<T, Timestamp?>.setToCurrentDate()

@JvmName(name = "setToCurrentTimestamp")
open fun KProperty1<T, Timestamp?>.setToCurrentDate()

Sets this field to the current timestamp.

If the field does not exist, this operator adds the field to the document.

The time Timestamp is internal. Instant should be preferred. For more information, see Timestamp.

Example

class User(
    val name: String?,
    val age: Int,
    val modificationDate: Timestamp,
)

collection.filter {
    User::name eq "Bob"
}.updateMany {
    User::age set 18
    User::modificationDate.setToCurrentDate()
}

External resources

setUnless

inline fun <V> Field<T, V>.setUnless(condition: Boolean, value: V)

inline fun <V> KProperty1<T, V>.setUnless(condition: Boolean, value: V)

Replaces the value of a field with the specified value, if condition is false.

If condition is true, this operator does nothing.

Example

class User(
    val name: String?,
    val age: Int,
)

collection.filter {
    User::name eq "foo"
}.updateMany {
    User::age.setUnless(someComplexOperation, 18)
}

External resources

See also

simplify

@LowLevelApi
abstract fun simplify(): BsonNode?

Returns a simplified (but equivalent) expression to the current expression.

timesAssign

inline operator fun <V : Number> Field<T, V>.timesAssign(amount: V)

inline operator fun <V : Number> KProperty1<T, V>.timesAssign(amount: V)

Multiplies a field by the specified amount.

If the field doesn't exist (either the document doesn't have it, or the operation is an upsert and a new document is created), the field is created with an initial value of 0.

Use of this operator with a field with a null value will generate an error.

Example

class User(
    val name: String,
    val price: Double,
)

collection.updateMany {
    User::price *= 2.0
}

External resources

toBson

Writes the result of simplifying to a new BsonDocument.

toString

abstract override fun toString(): String

JSON representation of this expression.

unsafe

open infix fun <Root, Child> KProperty1<Root, *>.unsafe(child: String): Field<Root, Child>

Refers to a field child of the current field, with no compile-time safety.

open infix fun <Root, Child> KProperty1<Root, *>.unsafe(child: KProperty1<*, Child>): Field<Root, Child>

Refers to a field child of the current field, without checking that it is a field available on the current object.

open infix fun <Root, Child> KProperty1<Root, *>.unsafe(child: Field<*, Child>): Field<Root, Child>

Refers to a field child of the current field, without checking that it is a field available on the current object.

open infix fun <Root, Child> Field<Root, *>.unsafe(child: KProperty1<*, Child>): Field<Root, Child>

Refers to a field child of the current field, without checking that it is a field available on the current object.

open infix fun <Root, Child> Field<Root, *>.unsafe(child: Field<*, Child>): Field<Root, Child>

Refers to a field child of the current field, without checking that it is a field available on the current object.

open infix fun <Root, Type, Child> Field<Root, Type>.unsafe(child: String): Field<Root, Child>

Refers to a field child of the current field, with no compile-time safety.

unset

abstract fun <V> Field<T, V>.unset()

open fun <V> KProperty1<T, V>.unset()

Deletes a field.

Example

class User(
    val name: String,
    val age: Int,
    val alive: Boolean,
)

collection.filter {
    User::name eq "Luke Skywalker"
}.updateOne {
    User::age.unset()
    User::alive set false
}

External resources

writeTo

@LowLevelApi
abstract override fun writeTo(writer: BsonFieldWriter)

Writes the result of simplifying this expression into writer.