MongoDB Basic

How to persist data using a MongoDB database.

Key takeaways

MongoDbPersistence Pip.Services component used to create MongoDB persistence objects that accept any type of data.
IdentifiableMongoDbPersistence Pip.Services component used to create MongoDB persistence objects that accept identifiable data objects.

Introduction

This tutorial will help you understand how to create persistence components for MongoDB. In particular, you will learn how to use two components, namely MongoDbPersistence and IdentifiableMongoDbPersistence. The explanations will include practical examples.

Persisting data with MongoDB

The Pip.Services toolkit provides two different components for MongoDB persistence. They are the MongoDbPersistence and the IdentifiableMongoDbPersistence classes respectively. The first can be used to persist objects of any type. The second is aimed at data items with unique ids. Both classes are part of the MongoDB module, persistence

General pre-requisites

In order to use any of these two components, we need to install the MongoDB module. This can be done with the following command:

npm install pip-services3-mongodb-nodex --save
dotnet add package PipServices3.Mongodb
go get -u github.com/pip-services3-gox/pip-services3-mongodb-gox@latest
dart pub add pip_services3_mongodb
pip install pip-services3-mongodb
Not available

Data object

Throughout the examples, we will use the data structure that appears below. It contains an id field, which can be used to identify each document. The next two fields (key and content) are generic and represent any type of content that we want to persist.

import { IStringIdentifiable } from 'pip-services3-commons-nodex';


export class MyData implements IStringIdentifiable {
    public id: string;
    public key: string;
    public content: string;
}

using System.Runtime.Serialization;

using PipServices3.Commons.Data;
using MongoDB.Bson.Serialization.Attributes;

[DataContract]
[BsonNoId]
[BsonIgnoreExtraElements]
public class MyData : IStringIdentifiable
{
    [BsonElement("id")]
    [DataMember(Name = "id")]
    public string Id { get; set; }

    [BsonElement("key")]
    [DataMember(Name = "key")]
    public string Key { get; set; }

    [BsonElement("content")]
    [DataMember(Name = "content")]
    public string Content { get; set; }
}

type MyData struct {
	Id      string `bson:"_id" json:"id"`
	Key     string `bson:"key" json:"key"`
	Content string `bson:"content" json:"content"`
}

type MyDataPage struct {
	Total *int64   `bson:"total" json:"total"`
	Data  []MyData `bson:"data" json:"data"`
}

import 'package:pip_services3_commons/pip_services3_commons.dart';


class MyData implements IStringIdentifiable, ICloneable {
  @override
  String? id;
  String? key;
  String? content;

  MyData();

  MyData.from(this.id, this.key, this.content);

  Map<String, dynamic> toJson() {
    return <String, dynamic>{'id': id, 'key': key, 'content': content};
  }

  void fromJson(Map<String, dynamic> json) {
    id = json['id'];
    key = json['key'];
    content = json['content'];
  }

  @override
  MyData clone() {
    return MyData.from(id, key, content);
  }
}

from pip_services3_commons.data import IStringIdentifiable

class MyData(IStringIdentifiable): 
    def __init__(self, id: str = None, key: str = None, content: str = None): 
        self.id = id 
        self.key = key 
        self.content = content 
Not available

In addition, we create three instances of this class, which we will use in the examples for CRUD operations.

let data1: MyData = { id: "1", key: "key 1", content: "content 1" };
let data2: MyData = { id: "2", key: "key 2", content: "content 2" };
let data3: MyData = { id: "3", key: "key 3", content: "content 3" };

var data1 = new MyData { Id = "1", Key = "key 1", Content="content 1" };
var data2 = new MyData { Id = "2", Key = "key 2", Content="content 2" };
var data3 = new MyData { Id = "3", Key = "key 3", Content="content 3" };

data1 := MyData{Id: "1", Key: "key 1", Content: "content 1"}
data2 := MyData{Id: "2", Key: "key 2", Content: "content 2"}
data3 := MyData{Id: "3", Key: "key 3", Content: "content 3"}

var data1 = MyData.from('1', 'key 1', 'content 1');
var data2 = MyData.from('2', 'key 2', 'content 2');
var data3 = MyData.from('3', 'key 3', 'content 3');

data1 = MyData('1', 'key 1', 'content 1') 
data2 = MyData('2', 'key 2', 'content 2') 
data3 = MyData('3', 'key 3', 'content 3') 
Not available

MongoDbPersistence

This component can be used with any type of data object. However, all documents stored in MongoDB are identifiable, that is, they have a unique id value. This means that even if we don’t assign a unique identifier to our object, MongoDB will assign one automatically. That is the reason behind having an id field in our data structure.

Pre-requisites

To use the MongoDbPersistence component we need to insert it first. This can be done with the following command:

import { MongoDbPersistence } from 'pip-services3-mongodb-nodex';
using PipServices3.MongoDb.Persistence;
import (
	mpersist "github.com/pip-services3-gox/pip-services3-mongodb-gox/persistence"
)
import 'package:pip_services3_mongodb/pip_services3_mongodb.dart';

from pip_services3_mongodb.persistence import MongoDbPersistence
Not available
Component creation

To create our MongoDB persistence component, we create a class that extends the MongoDbPersistence class. We also define an instance of this class and configure it using the configure method available from its parent class. As this method requires an input of type ConfigParams, we import this component and define the host, port, and database. Finally, we open the persistence component. Our code will look something like this:

export class MyMongoDbPersistence extends MongoDbPersistence<MyData> {
    public constructor() {
        super('mydata');
    }
}
        
let persistence = new MyMongoDbPersistence();

let config = ConfigParams.fromTuples(
    "connection.host", "localhost",
    "connection.port", 27017,
    "connection.database", "pipdatabase"
);
persistence.configure(config);

await persistence.open(null);

public class MyMongoDbPersistence : MongoDbPersistence<MyData>
{
    public MyMongoDbPersistence(): base("mydata") { }
}
        
var persistence = new MyMongoDbPersistence();

var config = ConfigParams.FromTuples(
    "connection.host", "localhost",
    "connection.port", 27017,
    "connection.database", "pipdatabase"
);
persistence.Configure(config);

await persistence.OpenAsync("123");


import (
	"reflect"

	conf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	mpersist "github.com/pip-services3-gox/pip-services3-mongodb-gox/persistence"
)

type MyMongoDbPersistence struct {
	*mpersist.MongoDbPersistence[MyData]
}

func NewMyMongoDbPersistence() *MyMongoDbPersistence {
	c := &MyMongoDbPersistence{}
	c.MongoDbPersistence = mpersist.InheritMongoDbPersistence(c, "mydata")
	return c
}

persistence := NewMyMongoDbPersistence()
config := conf.NewConfigParamsFromTuples(
	"connection.host", "localhost",
	"connection.port", 27017,
	"connection.database", "pipdatabase",
)
persistence.Configure(context.Backgroudn(), config)

err := persistence.Open(context.Backgroudn(), "")

class MyMongoDbPersistence extends MongoDbPersistence<MyData> {
  MyMongoDbPersistence() : super('mydata');
}
        
var persistence = MyMongoDbPersiste
var config = ConfigParams.fromTuple
  'connection.host', 'localhost',
  'connection.port', 27017,
  'connection.database', 'pipdatabase'
]);

persistence.configure(config);
await persistence.open('123');

class MyMongoDbPersistence(MongoDbPersistence):
    
    def __init__(self):
        super(MyMongoDbPersistence, self).__init__("mydata")
        
persistence = MyMongoDbPersistence()

from pip_services3_commons.config import ConfigParams

config = ConfigParams.from_tuples(
    'connection.host', 'localhost', 
    'connection.port', 27017, 
    'connection.database', 'pipdatabase'
)

persistence.configure(config)

persistence.open("123")
Not available

Later on, once all operations have been completed, we can close our persistence component with the close() method.

await persistence.open(null);
await persistence.OpenAsync("123");
err := persistence.Open(context.Background(), "")
await persistence.open('123');
persistence.close(None)
Not available
CRUD operations

Our class inherits several methods from its parent class that can be used to perform CRUD operations. This section explores them.

Create

To store a document, we use the create method. This method asks for the correlationId and the data object. In the following example, we create a document based on the previously defined data1 object.

let result = await persistence.create(null, data1);
var result = await persistence.CreateAsync(null, data1);
item, err := persistence.Create(context.Background(), "", data1)
var res = await persistence.create(null, data1);
result = persistence.create(None, data1)
Not available

Which returns:

result.id;      // Returns '1'
result.key;     // Returns 'key 1'
result.content; // Returns 'content 1'
result.Id;      // Returns '1'
result.Key;     // Returns 'key 1'
result.Content; // Returns 'content 1'
result.Id      // Returns '1'
result.Key     // Returns 'key 1'
result.Content // Returns 'content 1'
result.id;      // Returns '1'
result.key;     // Returns 'key 1'
result.content; // Returns 'content 1'
result.id       # Returns '1'
result.key     # Returns 'key 1'
result.content # Returns 'content 1'
Not available
Read

The MongoDbPersistence class offers several options to extract documents from a database.

getOneRandom()

As its name suggests, this method retrieves a random document based on a given filter. In the following example, we ask to retrieve a component with a key value of ‘key 3’.

import { FilterParams } from 'pip-services3-commons-nodex';

let item = await persistence.getOneRandom(null, FilterParams.fromTuples("key", "key 3"));
using PipServices3.Commons.Data;

var item = await persistence.GetOneRandomAsync(null, FilterParams.FromTuples("key", "key 3"));
import (
    cdata "github.com/pip-services3-gox/pip-services3-commons-gox/data"
)

item, err = persistence.GetOneRandom(context.Background(), "", cdata.NewFilterParamsFromTuples("key", "key 3"))
import 'package:pip_services3_commons/pip_services3_commons.dart';

var item = await persistence.getOneRandom(null, FilterParams.fromTuples(['key', 'key 3']));
from pip_services3_commons.data import FilterParams

result = persistence.get_one_random(None, FilterParams.from_tuples('key', 'key 3'))
Not available

Which returns:

result.id;      // Returns '3'
result.key;     // Returns 'key 3'
result.content; // Returns 'content 3'
result.Id;      // Returns '3'
result.Key;     // Returns 'key 3'
result.Content; // Returns 'content 3'
result.Id      // Returns '3'
result.Key     // Returns 'key 3'
result.Content // Returns 'content 3'
result.id;      // Returns '3'
result.key;     // Returns 'key 3'
result.content; // Returns 'content 3'
result.id      # Returns '3'
result.key     # Returns 'key 3'
result.content # Returns 'content 3'
Not available

getListByFilter()

This method gets a list of data items retrieved according to a given filter. In order to use it, we override this method. This action allows us to introduce any specific aspects that we may need. Our function will look something like this:

    public getListByFilter(correlationId: string, filter: FilterParams, sort: SortParams): Promise<MyData[]> {
        return super.getListByFilter(correlationId, this.composeFilter(filter), this.composeSort(sort), null);
    }
    public Task<List<MyData>> GetListByFilterAsync(string correlationId, FilterParams filterParams, SortParams sortParams = null)
    {
        return base.GetListByFilterAsync(correlationId, ComposeFilter(filterParams), ComposeSort(sortParams));
    }

func (c *MyMongoDbPersistence) GetListByFilter(ctx context.Context, correlationId string, filter *cdata.FilterParams, sort *cdata.SortParams) (items []MyData, err error) {
	return c.MongoDbPersistence.GetListByFilter(ctx, correlationId, c.composeFilter(filter), c.composeSort(sort), nil)
}
    Future<List<MyData>> getListByFilter(
    String? correlationId, FilterParams? filter, SortParams? sort) {
  return super.getListByFilterEx(
      correlationId, composeFilter(filter), composeSort(sort));
    }
    def get_list_by_filter(self, correlation_id: Optional[str], filter: FilterParams, sort: SortParams) -> List[MyData]:
         return super().get_list_by_filter(correlation_id, self._compose_filter(filter), None, self._compose_sort(sort))
Not available

Once we have our class defined, we can call it to get our search results. For example, to get all the elements with a key value of ‘key 3’ we can write:

let list = await persistence.getListByFilter("123", FilterParams.fromTuples("key", "key 3"), null);
var list = await persistence.GetListByFilterAsync("123", FilterParams.FromTuples("key", "key 3"), null);
list, err := persistence.GetListByFilter(context.Background(), "", cdata.NewFilterParamsFromTuples("key", "key 3"), nil)
var list = await persistence.getListByFilter('123', FilterParams.fromTuples(['key', 'key 3']), null);
result = persistence.get_list_by_filter('123', FilterParams.from_tuples('key', 'key 3'), None) 
Not available

Which returns:

result[0].id;      // Returns '3'
result[0].key;     // Returns 'key 3'
result[0].content; // Returns 'content 3'
result[0].Id;      // Returns '3'
result[0].Key;     // Returns 'key 3'
result[0].Content; // Returns 'content 3'
result[0].Id      // Returns '3'
result[0].Key     // Returns 'key 3'
result[0].Content // Returns 'content 3'
result[0].id;      // Returns '3'
result[0].key;     // Returns 'key 3'
result[0].content; // Returns 'content 3'
result[0].id      # Returns '3'
result[0].key     # Returns 'key 3'
result[0].content # Returns 'content 3'
Not available

getPageByFilter()

This method gets a page of data items retrieved according to a given filter. It also allows adding a sorting parameter and a projection object. Similar to what we did in the previous example, we override this method in our persistence class. Besides, we add two methods, namely composeFilter and composeSort. These two methods are used to define aspects that are specific to the database we are using (In our case MongoDB). An example of both methods is:

    private composeFilter(filter: FilterParams): any {
        filter = filter || new FilterParams();
        let criteria = [];

        let key = filter.getAsNullableString('key');
        if (key != null)
            criteria.push({ key: key });

        return criteria.length > 0 ? { $and: criteria } : null;
    }

    private composeSort(sort: SortParams): any {
        sort = sort || new SortParams();
        let sortCondition = {};

        for (let field of sort) {
            sortCondition[field.name] = field.ascending ? 1 : 0;
        }

        return sortCondition;
    }
    protected FilterDefinition<MyData> ComposeFilter(FilterParams filterParams)
    {
        filterParams = filterParams ?? new FilterParams();

        var builder = Builders<MyData>.Filter;
        var filter = builder.Empty;

        var key = filterParams.GetAsNullableString("key");

        if (key != null)
            filter &= builder.Eq("key", key);

        return filter;
    }

    protected SortDefinition<MyData> ComposeSort(SortParams sortParams)
    {
        sortParams = sortParams ?? new SortParams();

        var builder = Builders<MyData>.Sort;
        var sortDefinitions = new List<SortDefinition<MyData>>();

        foreach (var field in sortParams)
        {
            if (field.Ascending)
                sortDefinitions.Add(builder.Ascending(field.Name));
            else
                sortDefinitions.Add(builder.Descending(field.Name));
        }

        var sort = builder.Combine(sortDefinitions);

        return sort;
    }
func (c *MyMongoDbPersistence) composeFilter(filter *cdata.FilterParams) bson.M {
	if &filter == nil || filter == nil {
		filter = cdata.NewEmptyFilterParams()
	}

	key := filter.GetAsNullableString("key")
	var filterObj bson.M
	if *key != "" {
		filterObj = bson.M{"key": *key}
	} else {
		filterObj = bson.M{}
	}

	return filterObj
}

func (c *MyMongoDbPersistence) composeSort(sort *cdata.SortParams) bson.M {
	if &sort == nil || sort == nil {
		sort = cdata.NewEmptySortParams()
	}

	sortObj := bson.M{}

	for _, field := range *sort {
		if field.Ascending {
			sortObj[field.Name] = 1
		} else {
			sortObj[field.Name] = -1
		}

	}

	return sortObj
}
  Map<String, dynamic> composeFilter(FilterParams? filter) {
    filter = filter ?? FilterParams();
    var key = filter.getAsNullableString('key');

    var filterCondition = <String, dynamic>{};
    if (key != null) {
      filterCondition['key'] = key;
    }
    return filterCondition;
  }

  Map<String, dynamic> composeSort(SortParams? sort) {
    sort = sort ?? SortParams(null);

    var sortCondition = <String, dynamic>{};
    for (var field in sort) {
      sortCondition[field.name!] = field.ascending ? 1 : -1;
    }
    return sortCondition;
  }
   def _compose_filter(self, filter: FilterParams):
        filter = filter or FilterParams()
        key = filter.get_as_nullable_string('key')

        filter_condition = {}

        if key is not None:
            filter_condition['key'] = key
    
        return filter_condition

    def _compose_sort(self, sort: SortParams):
        sort = sort or SortParams()
        compose_sort = ''

        for i, filed in enumerate(sort):
            compose_sort += filed.name + (' ASC' if filed.ascending else ' DESC')

        return compose_sort
Not available

And, an example of get_page_by_filter() is:

    public getPageByFilter(correlationId: string, filter: FilterParams, paging: PagingParams, sort: SortParams): Promise<DataPage<MyData>> {
        return super.getPageByFilter(correlationId, this.composeFilter(filter), paging, this.composeSort(sort), null);
    }
    public Task<DataPage<MyData>> GetPageByFilterAsync(string correlationId, FilterParams filterParams, PagingParams paging = null,     SortParams sortParams = null)
    {
        return base.GetPageByFilterAsync(correlationId, ComposeFilter(filterParams), paging, ComposeSort(sortParams));
    }
func (c *MyMongoDbPersistence) GetPageByFilter(ctx context,Context, correlationId string, filter *cdata.FilterParams, paging *cdata.PagingParams, sort *cdata.SortParams) (page *DataPage[MyData], err error) {

	return c.MongoDbPersistence.GetPageByFilter(ctx, correlationId,
		c.composeFilter(filter), paging,
		c.composeSort(sort), nil)
}
  Future<DataPage<MyData>> getPageByFilter(String? correlationId,
      FilterParams? filter, PagingParams? paging, SortParams? sort) async {
    return super.getPageByFilterEx(
        correlationId, composeFilter(filter), paging, composeSort(sort));
  }
    def get_page_by_filter(self, correlation_id: Optional[str], filter: FilterParams, paging: PagingParams,
                           sort: SortParams) -> DataPage:
        return super().get_page_by_filter(correlation_id, self._compose_filter(filter), paging, self._compose_sort(sort), None)
Not available

Now, we can call this method from our persistence object. For example, to obtain all the records with a key value of ‘key 3’, we can write:

let page = await persistence.getPageByFilter(null, FilterParams.fromTuples("key", "key 3"), null, null);
var res = await persistence.GetPageByFilterAsync(null, FilterParams.FromTuples("key", "key 3"), null, null);
page, err := persistence.GetPageByFilter(context.Background(), "", cdata.NewFilterParamsFromTuples("key", "key 3"), nil, nil)
var page = await persistence.getPageByFilter('123', FilterParams.fromTuples(['key', 'key 3']), null, null);
result = persistence.get_page_by_filter(None, FilterParams.from_tuples("key", "key 3"), None, None)
Not available

which returns the searched values in a DataPage object:

result.data[0].id;       // Returns '3'
result.data[0].key;      // Returns 'key 3'
result.data[0].content;  // Returns 'content 3'
result.Data[0].Id;       // Returns '3'
result.Data[0].Key;      // Returns 'key 3'
result.Data[0].Content;  // Returns 'content 3'
result.Data[0].Id       // Returns '3'
result.Data[0].Key      // Returns 'key 3'
result.Data[0].Content  // Returns 'content 3'
result.data[0].id;       // Returns '3'
result.data[0].key;      // Returns 'key 3'
result.data[0].content;  // Returns 'content 3'
result.data[0].id       # Returns '3'
result.data[0].key      # Returns 'key 3'
result.data[0].content  # Returns 'content 3'
Not available

getCountByFilter()

This method gets the number of data items that will be retrieved based on a given filter. Because it is a private method in other languages – such as Node.js - we need to override it. Our added method will look similar to

    public getCountByFilter(correlationId: string, filter: FilterParams): Promise<number> {
        return super.getCountByFilter(correlationId, this.composeFilter(filter));
    }

    public Task<long> GetCountByFilterAsync(string correlationId, FilterParams filterParams)
    {
        return base.GetCountByFilterAsync(correlationId, ComposeSort(sortParams));
    }

func (c *MyMongoDbPersistence) GetCountByFilter(ctx context.Context, correlationId string, filter *cdata.FilterParams) (count int64, err error) {
	return c.MongoDbPersistence.GetCountByFilter(ctx, correlationId, c.composeFilter(filter))
}

  Future<int> getCountByFilter(
      String? correlationId, FilterParams? filter) async {
    return super.getCountByFilterEx(correlationId, composeFilter(filter));
  }

    def get_count_by_filter(self, correlation_id: Optional[str], filter: FilterParams) -> int:
        return super().get_count_by_filter(correlation_id, self._compose_filter(filter))
Not available

Now, we can call it from our code and get the returned amount of records that comply with a given condition, such as key equal to ‘key 3’.

let count = await persistence.getCountByFilter(null, FilterParams.fromTuples("key", "key 3"));
var count = await persistence.GetCountByFilterAsync(null, FilterParams.FromTuples("key", "key 3"), null); // Returns 1
count, err := persistence.GetCountByFilter(context.Background(), "", cdata.NewFilterParamsFromTuples("key", "key 3")) // Returns 1
var count = await persistence.getCountByFilter('123', FilterParams.fromTuples(['key', 'key 3']));
result = persistence.get_count_by_filter(None, FilterParams.from_tuples('key', 'key 3')) # Returns 1
Not available
Update

As MongoDbPersistence doesn’t have an update method, we need to define it in our class. We will see how to do this in the Example section.

Delete

The MongoDbPersistence class provides the deleteByFilter() method, which deletes all those documents that comply with a given condition. The following example shows how to delete all the elements with a key value equal to ‘key 3’:

await persistence.deleteByFilter(null, FilterParams.fromTuples("key", "key 3"));
await persistence.DeleteByFilterAsync(null, FilterParams.FromTuples("key", "key 3"));
err = persistence.DeleteByFilter(context.Background(), "", cdata.NewFilterParamsFromTuples("key", "key 3"))
await persistence.deleteByFilter(null, FilterParams.fromTuples(['key', 'key 3']));
persistence.delete_by_filter(None, FilterParams.from_tuples('key', 'key 3'))
Not available
Component’s final version

After overriding and adding the methods specified in the previous examples, our MongoDb persistence component looks like this:

export class MyMongoDbPersistence extends MongoDbPersistence<MyData> {
    public constructor() {
        super('mydata');
    }

    private composeFilter(filter: FilterParams): any {
        filter = filter || new FilterParams();
        let criteria = [];

        let key = filter.getAsNullableString('key');
        if (key != null)
            criteria.push({ key: key });

        return criteria.length > 0 ? { $and: criteria } : null;
    }

    private composeSort(sort: SortParams): any {
        sort = sort || new SortParams();
        let sortCondition = {};

        for (let field of sort) {
            sortCondition[field.name] = field.ascending ? 1 : 0;
        }

        return sortCondition;
    }

    public getOneRandom(correlationId: string, filter: FilterParams): Promise<MyData> {
        return super.getOneRandom(correlationId, this.composeFilter(filter));
    }

    public getListByFilter(correlationId: string, filter: FilterParams, sort: SortParams): Promise<MyData[]> {
        return super.getListByFilter(correlationId, this.composeFilter(filter), this.composeSort(sort), null);
    }

    public getPageByFilter(correlationId: string, filter: FilterParams, paging: PagingParams, sort: SortParams): Promise<DataPage<MyData>> {
        return super.getPageByFilter(correlationId, this.composeFilter(filter), paging, this.composeSort(sort), null);
    }

    public getCountByFilter(correlationId: string, filter: FilterParams): Promise<number> {
        return super.getCountByFilter(correlationId, this.composeFilter(filter));
    }

    public deleteByFilter(correlationId: string, filter: FilterParams): Promise<void> {
        return super.deleteByFilter(correlationId, this.composeFilter(filter));
    }
}

using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;

public class MyMongoDbPersistence : MongoDbPersistence<MyData>
{
    public MyMongoDbPersistence(): base("mydata") { }

    protected FilterDefinition<MyData> ComposeFilter(FilterParams filterParams)
    {
        filterParams = filterParams ?? new FilterParams();

        var builder = Builders<MyData>.Filter;
        var filter = builder.Empty;

        var key = filterParams.GetAsNullableString("key");

        if (key != null)
            filter &= builder.Eq("key", key);

        return filter;
    }

    protected SortDefinition<MyData> ComposeSort(SortParams sortParams)
    {
        sortParams = sortParams ?? new SortParams();

        var builder = Builders<MyData>.Sort;
        var sortDefinitions = new List<SortDefinition<MyData>>();

        foreach (var field in sortParams)
        {
            if (field.Ascending)
                sortDefinitions.Add(builder.Ascending(field.Name));
            else
                sortDefinitions.Add(builder.Descending(field.Name));
        }

        var sort = builder.Combine(sortDefinitions);

        return sort;
    }

    public Task<MyData> GetOneRandomAsync(string correlationId, FilterParams filterParams)
    {
        return base.GetOneRandomAsync(correlationId, ComposeFilter(filterParams));
    }

    public Task<List<MyData>> GetListByFilterAsync(string correlationId, FilterParams filterParams, SortParams sortParams = null)
    {
        return base.GetListByFilterAsync(correlationId, ComposeFilter(filterParams), ComposeSort(sortParams));
    }

    public Task<DataPage<MyData>> GetPageByFilterAsync(string correlationId, FilterParams filterParams, PagingParams paging = null, SortParams sortParams = null)
    {
        return base.GetPageByFilterAsync(correlationId, ComposeFilter(filterParams), paging, ComposeSort(sortParams));
    }

    public Task<long> GetCountByFilterAsync(string correlationId, FilterParams filterParams)
    {
        return base.GetCountByFilterAsync(correlationId, ComposeSort(sortParams));
    }

    public Task DeleteByFilterAsync(string correlationId, FilterParams filterParams)
    {
        return base.DeleteByFilterAsync(correlationId, ComposeFilter(filterParams));
    }
}

import (
	"reflect"

	conf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	cdata "github.com/pip-services3-gox/pip-services3-commons-gox/data"
	mpersist "github.com/pip-services3-gox/pip-services3-mongodb-gox/persistence"

	"go.mongodb.org/mongo-driver/bson"
)

type MyMongoDbPersistence struct {
	*mpersist.MongoDbPersistence
}

func NewMyMongoDbPersistence() *MyMongoDbPersistence {
	c := &MyMongoDbPersistence{}
	c.MongoDbPersistence = mpersist.InheritMongoDbPersistence(c, "mydata")
	return c
}

func (c *MyMongoDbPersistence) composeFilter(filter *cdata.FilterParams) bson.M {
	if &filter == nil || filter == nil {
		filter = cdata.NewEmptyFilterParams()
	}

	key := filter.GetAsNullableString("key")
	var filterObj bson.M
	if *key != "" {
		filterObj = bson.M{"key": *key}
	} else {
		filterObj = bson.M{}
	}

	return filterObj
}

func (c *MyMongoDbPersistence) composeSort(sort *cdata.SortParams) bson.M {
	if &sort == nil || sort == nil {
		sort = cdata.NewEmptySortParams()
	}

	sortObj := bson.M{}

	for _, field := range *sort {
		if field.Ascending {
			sortObj[field.Name] = 1
		} else {
			sortObj[field.Name] = -1
		}

	}

	return sortObj
}

func (c *MyMongoDbPersistence) GetListByFilter(ctx context.Context, correlationId string, filter *cdata.FilterParams, sort *cdata.SortParams) (items []MyData, err error) {
	return c.MongoDbPersistence.GetListByFilter(correlationId, c.composeFilter(filter), c.composeSort(sort), nil)
}

func (c *MyMongoDbPersistence) GetPageByFilter(ctx context.Context, correlationId string, filter *cdata.FilterParams, paging *cdata.PagingParams, sort *cdata.SortParams) (page *cdata.DataPage[MyData], err error) {

	return c.MongoDbPersistence.GetPageByFilter(ctx, correlationId,
		c.composeFilter(filter), paging,
		c.composeSort(sort), nil)
}

func (c *MyMongoDbPersistence) GetCountByFilter(ctx context.Context, correlationId string, filter *cdata.FilterParams) (count int64, err error) {
	return c.MongoDbPersistence.GetCountByFilter(ctx, correlationId, c.composeFilter(filter))
}

func (c *MyMongoDbPersistence) DeleteByFilter(ctx context.Context, correlationId string, filter *cdata.FilterParams) error {
	return c.MongoDbPersistence.DeleteByFilter(ctx, correlationId, c.composeFilter(filter))
}

import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_mongodb/pip_services3_mongodb.dart';

class MyMongoDbPersistence extends MongoDbPersistence<MyData> {
  MyMongoDbPersistence() : super('mydata');

  Map<String, dynamic> composeFilter(FilterParams? filter) {
    filter = filter ?? FilterParams();
    var key = filter.getAsNullableString('key');

    var filterCondition = <String, dynamic>{};
    if (key != null) {
      filterCondition['key'] = key;
    }
    return filterCondition;
  }

  Map<String, dynamic> composeSort(SortParams? sort) {
    sort = sort ?? SortParams(null);

    var sortCondition = <String, dynamic>{};
    for (var field in sort) {
      sortCondition[field.name!] = field.ascending ? 1 : -1;
    }
    return sortCondition;
  }

  Future<MyData?> getOneRandom(String? correlationId, FilterParams? filter) {
    return super.getOneRandomEx(correlationId, composeFilter(filter));
  }

  Future<List<MyData>> getListByFilter(
      String? correlationId, FilterParams? filter, SortParams? sort) {
    return super.getListByFilterEx(
        correlationId, composeFilter(filter), composeSort(sort));
  }

  Future<DataPage<MyData>> getPageByFilter(String? correlationId,
      FilterParams? filter, PagingParams? paging, SortParams? sort) async {
    return super.getPageByFilterEx(
        correlationId, composeFilter(filter), paging, composeSort(sort));
  }

  Future<int> getCountByFilter(
      String? correlationId, FilterParams? filter) async {
    return super.getCountByFilterEx(correlationId, composeFilter(filter));
  }

  Future deleteByFilter(String? correlationId, FilterParams? filter) {
    return super.deleteByFilterEx(correlationId, composeFilter(filter));
  }
}

class MyMongoDbPersistence(MongoDbPersistence):
    
    def __init__(self):
        super(MyMongoDbPersistence, self).__init__("mydata2")
   
    def _compose_filter(self, filter: FilterParams):
        filter = filter or FilterParams()
        key = filter.get_as_nullable_string('key')

        filter_condition = {}

        if key is not None:
            filter_condition['key'] = key
    
        return filter_condition

    def _compose_sort(self, sort: SortParams):
        sort = sort or SortParams()
        compose_sort = ''

        for i, filed in enumerate(sort):
            compose_sort += filed.name + (' ASC' if filed.ascending else ' DESC')

        return compose_sort


    def get_one_random(self, correlation_id: Optional[str], filter: FilterParams) -> MyData:
        return super().get_one_random(correlation_id, self._compose_filter(filter))

    def get_list_by_filter(self, correlation_id: Optional[str], filter: FilterParams, sort: SortParams) -> List[MyData]:
         return super().get_list_by_filter(correlation_id, self._compose_filter(filter), None, self._compose_sort(sort))
         
    def get_page_by_filter(self, correlation_id: Optional[str], filter: FilterParams, paging: PagingParams,
                           sort: SortParams) -> DataPage:
        return super().get_page_by_filter(correlation_id, self._compose_filter(filter), paging, self._compose_sort(sort), None)

    def get_count_by_filter(self, correlation_id: Optional[str], filter: FilterParams) -> int:
        return super().get_count_by_filter(correlation_id, self._compose_filter(filter))

    def delete_by_filter(self, correlation_id: Optional[str], filter: FilterParams):
        super().delete_by_filter(correlation_id, self._compose_filter(filter))
Not available
Example

Now, we will see a simple example that puts most of the learned concepts together. It starts by importing the necessary libraries and creating a MongoDB persistence class that includes an update method. Then, it performs CRUD operations and prints the results. The code is:

import { ConfigParams, DataPage, FilterParams, IStringIdentifiable, SortParams } from 'pip-services3-commons-nodex';
import { MongoDbPersistence } from 'pip-services3-mongodb-nodex';

export class MyData implements IStringIdentifiable {
    public id: string;
    public key: string;
    public content: string;
}

export class MyMongoDbPersistence extends MongoDbPersistence<MyData> {
    public constructor() {
        super('mydata');
    }

    private composeFilter(filter: FilterParams): any {
        filter = filter || new FilterParams();
        let criteria = [];

        let key = filter.getAsNullableString('key');
        if (key != null)
            criteria.push({ key: key });

        return criteria.length > 0 ? { $and: criteria } : null;
    }

    public getListByFilter(correlationId: string, filter: FilterParams, sort: SortParams): Promise<MyData[]> {
        return super.getListByFilter(correlationId, this.composeFilter(filter), null, null);
    }

    public async update(correlationId: string, item: MyData): Promise<MyData> {
        if (item == null || item.id == null) {
            return null;
        }

        let newItem = Object.assign({}, item);
        delete newItem.id;
        newItem = this.convertFromPublic(newItem);

        let filter = { _id: item.id };
        let update = { $set: newItem };
        let options = {
            returnDocument: "after"
        };

        let result = await new Promise<any>((resolve, reject) => {
            this._collection.findOneAndUpdate(filter, update, options, (err, result) => {
                if (err == null) resolve(result);
                else reject(err);
            });
        });

        newItem = result ? this.convertToPublic(result.value) : null;
        return newItem;
    }

    public deleteByFilter(correlationId: string, filter: FilterParams): Promise<void> {
        return super.deleteByFilter(correlationId, this.composeFilter(filter));
    }
}

export function printResult(operationName: string, res: MyData) {
    console.log(`==================== ${operationName} ====================`);
    console.log(`MyData with id: ${res.id}`);
    console.log(`MyData key: ${res.key}`);
    console.log(`MyData content: ${res.content}`);
}

let data1: MyData = { id: "1", key: "key 1", content: "content 1" };

let persistence = new MyMongoDbPersistence();

let config = ConfigParams.fromTuples(
    "connection.host", "localhost",
    "connection.port", 27017,
    "connection.database", "pipdatabase"
);
persistence.configure(config);

await persistence.open(null);
await persistence.clear(null);

// 1 - Create
let result = await persistence.create(null, data1);
printResult("Create", result);

// 2 - Retrieve
let items = await persistence.getListByFilter("123", FilterParams.fromTuples("key", "key 1"), null);
printResult("Get by id", items[0]);

// 3 - Update
items[0].content = "new content 2";
items[0].key = "key 2";

let update = await persistence.update(null, items[0]);
printResult("Update", update);

// 4 - Delete
await persistence.deleteByFilter(null, FilterParams.fromTuples("key", "key 1"));
await persistence.close(null);

using System;
using System.Runtime.Serialization;

using PipServices3.Commons.Data;
using PipServices3.Commons.Config;
using PipServices3.MongoDb.Persistence;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
using System.Collections.Generic;
using System.Threading.Tasks;


[DataContract]
[BsonNoId]
[BsonIgnoreExtraElements]
public class MyData : IStringIdentifiable
{
    [BsonElement("id")]
    [DataMember(Name = "id")]
    public string Id { get; set; }

    [BsonElement("key")]
    [DataMember(Name = "key")]
    public string Key { get; set; }

    [BsonElement("content")]
    [DataMember(Name = "content")]
    public string Content { get; set; }
}

public class MyMongoDbPersistence : MongoDbPersistence<MyData>
{
    public MyMongoDbPersistence(): base("mydata") { }

    protected FilterDefinition<MyData> ComposeFilter(FilterParams filterParams)
    {
        filterParams = filterParams ?? new FilterParams();

        var builder = Builders<MyData>.Filter;
        var filter = builder.Empty;

        var key = filterParams.GetAsNullableString("key");

        if (key != null)
            filter &= builder.Eq("key", key);

        return filter;
    }

    public Task<List<MyData>> GetListByFilterAsync(string correlationId, FilterParams filterParams, SortParams sortParams = null)
    {
        return base.GetListByFilterAsync(correlationId, ComposeFilter(filterParams), ComposeSort(sortParams));
    }

    public virtual async Task<MyData> UpdateAsync(string correlationId, MyData item)
    {
        if (item == null)
            return null;

        var filter = Builders<MyData>.Filter.Eq("id", item.Id);
        var options = new FindOneAndReplaceOptions<MyData>
        {
            ReturnDocument = ReturnDocument.After,
            IsUpsert = false
        };
        var result = await _collection.FindOneAndReplaceAsync(filter, item, options);

        _logger.Trace(correlationId, "Update in {0} with id = {1}", _collectionName, item.Id);

        return result;
    }

    public Task DeleteByFilterAsync(string correlationId, FilterParams filterParams)
    {
        return base.DeleteByFilterAsync(correlationId, ComposeFilter(filterParams));
    }
}

public static void PrintResult(string operationNme, MyData res)
{
    Console.WriteLine($"==================== {operationNme} ====================");
    Console.WriteLine($"MyData with Id: {res.Id}");
    Console.WriteLine($"MyData Key: {res.Key}");
    Console.WriteLine($"MyData Content: {res.Content}");
}


var data1 = new MyData { Id = "1", Key = "key 1", Content="content 1" };

persistence = new MyMongoDbPersistence();

var config = ConfigParams.FromTuples(
    "connection.host", "localhost",
    "connection.port", 27017,
    "connection.database", "mydb"
);

persistence.Configure(config);

await persistence.OpenAsync("123");
await persistence.ClearAsync("123");

// 1 - Create
var result = await persistence.CreateAsync(null, data1);
PrintResult("Create", result);

// 2 - Retrieve
var items = await persistence.GetListByFilterAsync("123", FilterParams.FromTuples("key", "key 1"), null);
PrintResult("Get by id", items[0]);

// 3 - Update
items[0].Content = "new content 2";
items[0].Key = "key 2";

var update = await persistence.UpdateAsync(null, items[0]);
PrintResult("Update", update);

// 4 - Delete
await  persistence.DeleteByFilterAsync(null, FilterParams.FromTuples("key", "key 1"));

await persistence.CloseAsync("123");

import (
	"fmt"
	"reflect"

	conf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	cdata "github.com/pip-services3-gox/pip-services3-commons-gox/data"
	datpersist "github.com/pip-services3-gox/pip-services3-data-gox/persistence"
	mpersist "github.com/pip-services3-gox/pip-services3-mongodb-gox/persistence"

	mngoptions "go.mongodb.org/mongo-driver/mongo/options"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
)


type MyMongoDbPersistence struct {
	*mpersist.MongoDbPersistence[MyData]
}

func NewMyMongoDbPersistence() *MyMongoDbPersistence {
	c := &MyMongoDbPersistence{}
	c.MongoDbPersistence = mpersist.InheritMongoDbPersistence(c, "mydata")
	return c
}

func (c *MyMongoDbPersistence) composeFilter(filter *cdata.FilterParams) bson.M {
	if &filter == nil || filter == nil {
		filter = cdata.NewEmptyFilterParams()
	}

	key := filter.GetAsNullableString("key")
	var filterObj bson.M
	if *key != "" {
		filterObj = bson.M{"key": *key}
	} else {
		filterObj = bson.M{}
	}

	return filterObj
}

func (c *MyMongoDbPersistence) Update(ctx context.Context, correlationId string, item MyData) (result MyData, err error) {
	newItem := c.ConvertFromPublic(item)
	id := newItem["_id"]
	filter := bson.M{"_id": id}
	update := bson.D{{"$set", newItem}}
	var options mngoptions.FindOneAndUpdateOptions
	retDoc := mngoptions.After
	options.ReturnDocument = &retDoc
	fuRes := c.Collection.FindOneAndUpdate(ctx, filter, update, &options)
	if fuRes.Err() != nil {
		return result, fuRes.Err()
	}
	c.Logger.Trace(correlationId, "Updated in %s with id = %s", c.CollectionName, id)
	var docPointer T
	err = fuRes.Decode(&docPointer)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return result, nil
		}
		return result, err
	}

	result = c.Overrides.ConvertToPublic(docPointer)
	return result, nil
}

func (c *MyMongoDbPersistence) GetListByFilter(ctx context.Context, correlationId string, filter *cdata.FilterParams, sort *cdata.SortParams) (items []MyData, err error) {
	return c.MongoDbPersistence.GetListByFilter(ctx, correlationId, c.composeFilter(filter), c.composeSort(sort), nil)
}

func (c *MyMongoDbPersistence) DeleteByFilter(ctx context.Context, correlationId string, filter *cdata.FilterParams) error {
	return c.MongoDbPersistence.DeleteByFilter(ctx, correlationId, c.composeFilter(filter))
}

type MyData struct {
	Id      string `bson:"_id" json:"id"`
	Key     string `bson:"key" json:"key"`
	Content string `bson:"content" json:"content"`
}

type MyDataPage struct {
	Total *int64   `bson:"total" json:"total"`
	Data  []MyData `bson:"data" json:"data"`
}


func PrintResult(operationName string, res MyData) {
	fmt.Println("==================== " + operationName + " ====================")
	fmt.Println("MyData with Id: " + res.Id)
	fmt.Println("MyData with Key: " + res.Key)
	fmt.Println("MyData with Content: " + res.Content)
}

func main() {
	data1 := MyData{Id: "1", Key: "key 1", Content: "content 1"}

	persistence := NewMyMongoDbPersistence()
	config := conf.NewConfigParamsFromTuples(
		"connection.host", "localhost",
		"connection.port", 27017,
		"connection.database", "pipdatabase",
	)
	persistence.Configure(context.Background(), config)

	_ = persistence.Open(context.Background(), "")
	_ = persistence.Clear(context.Background(), "")

	// 1 - Create
	result, _ := persistence.Create(context.Background(), "123", data1)
	PrintResult("Create", result)

	// 2 - Retrieve
	items, _ := persistence.GetListByFilter(context.Background(), "123", cdata.NewFilterParamsFromTuples("key", "key 1"), nil)
	PrintResult("Get by id", items[0])

	// 3 - Update
	items[0].Content = "new content 2"
	items[0].Key = "key 2"

	update, _ := persistence.Update(context.Background(), "123", items[0])
	PrintResult("Update", update)

	// 4 - Delete
	_ = persistence.DeleteByFilter(context.Background(), "123", cdata.NewFilterParamsFromTuples("key", "key 1"))

	_ = persistence.Close(context.Background(), "123")
}

import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_mongodb/pip_services3_mongodb.dart';

class MyData implements IStringIdentifiable, ICloneable {
  @override
  String? id;
  String? key;
  String? content;

  MyData();

  MyData.from(this.id, this.key, this.content);

  Map<String, dynamic> toJson() {
    return <String, dynamic>{'id': id, 'key': key, 'content': content};
  }

  void fromJson(Map<String, dynamic> json) {
    id = json['id'];
    key = json['key'];
    content = json['content'];
  }

  @override
  MyData clone() {
    return MyData.from(id, key, content);
  }
}

class MyMongoDbPersistence extends MongoDbPersistence<MyData> {
  MyMongoDbPersistence() : super('mydata');

  Map<String, dynamic> composeFilter(FilterParams? filter) {
    filter = filter ?? FilterParams();
    var key = filter.getAsNullableString('key');

    var filterCondition = <String, dynamic>{};
    if (key != null) {
      filterCondition['key'] = key;
    }
    return filterCondition;
  }

  Future<MyData?> update(String? correlationId, MyData? item) async {
    if (item == null || item.id == null) {
      return null;
    }
    var jsonMap = convertFromPublic(item, createUid: false);
    jsonMap?.remove('_id');
    var filter = {'_id': item.id};
    var update = {r'$set': jsonMap};
    var result = await collection?.findAndModify(
        query: filter, update: update, returnNew: true, upsert: false);

    return result != null ? convertToPublic(result) : null;
  }

  Future<List<MyData>> getListByFilter(
      String? correlationId, FilterParams? filter, SortParams? sort) {
    return super.getListByFilterEx(
        correlationId, composeFilter(filter), composeSort(sort));
  }

  Future deleteByFilter(String? correlationId, FilterParams? filter) {
    return super.deleteByFilterEx(correlationId, composeFilter(filter));
  }
}

void printResult(String operationName, MyData res) {
  print('==================== $operationName ====================');
  print('MyData with id: ${res.id}');
  print('MyData key: ${res.key}');
  print('MyData content: ${res.content}');
}

void main(List<String> arguments) async {
  var data1 = MyData.from('1', 'key 1', 'content 1');

  var persistence = MyMongoDbPersistence();

  var config = ConfigParams.fromTuples([
    'connection.host',
    'localhost',
    'connection.port',
    27017,
    'connection.database',
    'pipdatabase'
  ]);
  persistence.configure(config);

  await persistence.open(null);
  await persistence.clear(null);

  // 1 - Create
  var result = await persistence.create(null, data1);
  printResult('Create', result!);

  // 2 - Retrieve
  var items = await persistence.getListByFilter(
      '123', FilterParams.fromTuples(['key', 'key 1']), null);
  printResult('Get by id', items[0]);

  // 3 - Update
  items[0].content = 'new content 2';
  items[0].key = 'key 2';

  var update = await persistence.update(null, items[0]);
  printResult('Update', update!);

  // 4 - Delete
  await persistence.deleteByFilter(
      null, FilterParams.fromTuples(['key', 'key 1']));
  await persistence.close(null);
}

from copy import deepcopy
from typing import Optional, Any

import pymongo
from pip_services3_commons.config import ConfigParams
from pip_services3_commons.data import IStringIdentifiable, FilterParams
from pip_services3_mongodb.persistence import MongoDbPersistence


class MyData(IStringIdentifiable):
    def __init__(self, id: str = None, key: str = None, content: str = None):
        self.id = id
        self.key = key
        self.content = content

class MyMongoDbPersistence(MongoDbPersistence):

    def __init__(self):
        super(MyMongoDbPersistence, self).__init__("mydata")

    def _compose_filter(self, filter: FilterParams):
        filter = filter or FilterParams()
        key = filter.get_as_nullable_string('key')

        filter_condition = {}

        if key is not None:
            filter_condition['key'] = key
    
        return filter_condition
    
    def get_list_by_filter(self, correlation_id: Optional[str], filter: FilterParams, sort: SortParams) -> List[MyData]:

         return super().get_list_by_filter(correlation_id, self._compose_filter(filter), None, None)
        
    def update(self, correlation_id: Optional[str], item: Any) -> Any:
        if item is None or item.id is None:
            return
        new_item = deepcopy(item)
        new_item = self._convert_from_public(new_item)
        _id = item.id

        result = self._collection.find_one_and_update(
            {'_id': _id}, {'$set': new_item},
            return_document=pymongo.ReturnDocument.AFTER
        )

        new_item = self._convert_to_public(result)

        return new_item

    def delete_by_filter(self, correlation_id: Optional[str], filter: FilterParams):
        super().delete_by_filter(correlation_id, self._compose_filter(filter))


data1 = MyData(None, 'key 1', 'content 1')

persistence = MyMongoDbPersistence()

config = ConfigParams.from_tuples(
    'connection.host', 'localhost', 
    'connection.port', 27017, 
    'connection.database', 'mydb'
)

persistence.configure(config)

persistence.open("123")
persistence.clear("123")


def print_result(operation_name: str, res: MyData):
    print(f"==================== {operation_name} ====================")
    print(f'MyData with Id: {res.id}')
    print(f'MyData Key: {res.key}')
    print(f'MyData Content: {res.content}')


# CRUD
# 1 - Create
result = persistence.create(None, data1)
print_result('Create', result)

# 2 - Retrieve
items = persistence.get_list_by_filter('123', FilterParams.from_tuples('key', 'key 1'), None)  
print_result('Get by id', items[0])

# 3 - Update
items[0].content = 'new content 2'
items[0].key = 'key 2'

update = persistence.update(None, items[0])  
print_result('Update', update)

# 4 - Delete
persistence.delete_by_filter(None, FilterParams.from_tuples('key', 'key 1')) 

persistence.close("123")

Not available

And the output is:

figure 1

IdentifiableMongoDbPersistence

This component is used to perform CRUD operations with identifiable data objects, that is, objects that can be identified via a unique id.

Pre-requisites

To use the IdentifiableMongoDbPersistence component we need to import it first. This can be done with the following command:

import { IdentifiableMongoDbPersistence } from 'pip-services3-mongodb-nodex';
using PipServices3.MongoDb.Persistence;
import (
    mpersist "github.com/pip-services3-gox/pip-services3-mongodb-gox/persistence"
)
import 'package:pip_services3_mongodb/pip_services3_mongodb.dart';
from pip_services3_mongodb.persistence import IdentifiableMongoDbPersistence
Not available
Component creation

To create an identifiable MongoDB persistence component, we create a subclass of the IdentifiableMongoDbPersistence class where we specify the name of the table we will be using (In our example: mydata). We also define an instance of it and, via the configure() method, we add the connection parameters. In our example, we use a local database and we connect to it through the default port 27017. We also define a database named “pipdatabase”.

import { ConfigParams } from 'pip-services3-commons-nodex';

export class MyIdentifiableMongoDbPersistence extends IdentifiableMongoDbPersistence<MyData, string> {
    public constructor() {
        super("mydata");
    }
}
let persistence = new MyIdentifiableMongoDbPersistence();

let config = ConfigParams.fromTuples(
    "connection.host", "localhost",
    "connection.port", 27017,
    "connection.database", "pipdatabase"
);

persistence.configure(config);
using PipServices3.Commons.Config;

public class MyIdentifiableMongoDbPersistence: IdentifiableMongoDbPersistence<MyData, string>
{
    public MyIdentifiableMongoDbPersistence() : base("mydata") { }
}

var persistence = new MyMongoDbPersistence();

var config = ConfigParams.FromTuples(
    "connection.host", "localhost",
    "connection.port", 27017,
    "connection.database", "pipdatabase"
);

persistence.Configure(config);
import (
    "fmt"
	"reflect"

	conf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	cdata "github.com/pip-services3-gox/pip-services3-commons-gox/data"
	mpersist "github.com/pip-services3-gox/pip-services3-mongodb-gox/persistence"
)

type MyIdentifiableMongoDbPersistence struct {
	*mpersist.IdentifiableMongoDbPersistence[MyData, string]
}

func NewMyIdentifiableMongoDbPersistencee() *MyIdentifiableMongoDbPersistence {
	c := &MyIdentifiableMongoDbPersistence{}
	c.IdentifiableMongoDbPersistence = *mpersist.InheritIdentifiableMongoDbPersistence(c, "mydata")
	return c
}

persistence := NewMyIdentifiableMongoDbPersistencee()
config := conf.NewConfigParamsFromTuples(
	"connection.host", "localhost",
	"connection.port", 27017,
	"connection.database", "pipdatabase",
)
persistence.Configure(context.Background(), config)
import 'package:pip_services3_commons/pip_services3_commons.dart';

class MyIdentifiableMongoDbPersistence
    extends IdentifiableMongoDbPersistence<MyData, String> {
  MyIdentifiableMongoDbPersistence() : super('mydata');
}

var persistence = MyIdentifiableMongoDbPersistence();
var config = ConfigParams.fromTuples([
  'connection.host','localhost',
  'connection.port', 27017,
  'connection.database', 'pipdatabase'
]);

persistence.configure(config);
class MyIdentifiableMongoDbPersistence(IdentifiableMongoDbPersistence):
    
    def __init__(self):
        super(MyIdentifiableMongoDbPersistence, self).__init__("mydata")
        
persistence = MyIdentifiableMongoDbPersistence()

from pip_services3_commons.config import ConfigParams

config = ConfigParams.from_tuples(
    'connection.host', 'localhost', 
    'connection.port', 27017, 
    'connection.database', 'pipdatabase'
)

persistence.configure(config)
Not available

And, after creating it, we open the connection.

await persistence.open(null);
await persistence.OpenAsync(null);
_ = persistence.Open(context.Background(), "")
await persistence.open(null);
persistence.open("123")
Not available

Later on, once we have finished using this persistence component, we can close it with the close() method.

await persistence.clear(null);
await persistence.CloseAsync(null);
_ = persistence.Clear(context.Background(), "")
await persistence.clear(null);
persistence.close(None)
Not available
CRUD operations

This class presents a set of methods for CRUD operations. This section explains their usage and provides examples for each of them.

Create

This component presents two methods that allow us to create a document in MongoDB. They are:

Read

create()

To add a new document to our collection, we can use the create() method, which accepts the correlationId and the data item as inputs. The example below shows how to use it.

let result = await persistence.create(null, data1);
var result = await persistence.CreateAsync(null, data1);
result, _ := persistence.Create(context.Background(), "123", data1)
var result = await persistence.create(null, data1);
result = persistence.create(None, data1)
Not available

Which returns:

result.id;      // Returns '1'
result.key;     // Returns 'key 1'
result.content; // Returns 'content 1'
result.Id;      // Returns '1'
result.Key;     // Returns 'key 1'
result.Content; // Returns 'content 1'
result.Id      // Returns '1'
result.Key     // Returns 'key 1'
result.Content // Returns 'content 1'
result.id;      // Returns '1'
result.key;     // Returns 'key 1'
result.content; // Returns 'content 1'
result.id      # Returns '1'
result.key     # Returns 'key 1'
result.content # Returns 'content 1'
Not available

set()

This method updates an existing data item. If the item doesn’t exist, it creates it. The example below shows how to use it.

data1 = { id: "1", key: "key 1", content: "new content 1" };
result = await persistence.set(null, data1);
data1 = new MyData { Id = "1", Key = "key 1", Content = "new content 1" };
result = await persistence.SetAsync(null, data1);
data1 = MyData{Id: "1", Key: "key 1", Content: "new content 1"}
result, _ = persistence.Set(context.Background(), "123", data1)
data1 = MyData.from('1', 'key 1', 'new content 1');
result = await persistence.set('123', data1);
data1 = MyData('1', 'key 1', 'new content 1') 
result = persistence.set(None, data1)
Not available

Which returns:

result.id;      // Returns '1'
result.key;     // Returns 'key 1'
result.content; // Returns 'new content 1'
result.Id;      // Returns '1'
result.Key;     // Returns 'key 1'
result.Content; // Returns 'new content 1'
result.Id      // Returns '1'
result.Key     // Returns 'key 1'
result.Content // Returns 'new content 1'
result.id;      // Returns '1'
result.key;     // Returns 'key 1'
result.content; // Returns 'new content 1'
result.id      # Returns '1'
result.key     # Returns 'key 1'
result.content # Returns 'new content 1'
Not available

get_one_by_id()

To retrieve a data object, we can use the get_one_by_id method, which allows for the selection of a data object based on its id. In the following example, we obtain the item with key = ‘1’.

result = await persistence.getOneById(null, "1");
result = await persistence.GetOneByIdAsync(null, "1");
result, _ = persistence.GetOneById(context.Background(), "123", "1")
result = await persistence.getOneById(null, '1');
result = persistence.get_one_by_id(None, '1')
Not available

Which returns:

result.id;      // Returns '1'
result.key;     // Returns 'key 1'
result.content; // Returns 'content 1'
result.Id;      // Returns '1'
result.Key;     // Returns 'key 1'
result.Content; // Returns 'content 1'
result.Id      // Returns '1'
result.Key     // Returns 'key 1'
result.Content // Returns 'content 1'
result.id;      // Returns '1'
result.key;     // Returns 'key 1'
result.content; // Returns 'content 1'
result.id      # Returns '1'
result.key     # Returns 'key 1'
result.content # Returns 'content 1'
Not available

getListByIds()

We can also use the getListByIds() method, which is similar to the previous one, but accepts a list containing ids and retrieves the documents related to those ids. In the following example, we search for those items with id equal to ‘1’ and ‘2’.

let resList = await persistence.getListByIds(null, ["1", "2"]);
var resList = await persistence.GetListByIdsAsync(null, new string[] { "1", "2"});
list, _ := persistence.GetListByIds(context.Background(), "123", []string{"1", "2"})
var resList = await persistence.getListByIds(null, ['1', '2']);
result = persistence.get_list_by_ids(None, ['1','2'])
Not available

Which returns:

result[0].id;      // Returns '1'
result[0].key;     // Returns 'key 1'
result[0].content; // Returns 'content 1'
result[1].id;      // Returns '2'
result[1].key;     // Returns 'key 2'
result[1].content; // Returns 'content 2'
result[0].Id;      // Returns '1'
result[0].Key;     // Returns 'key 1'
result[0].Content; // Returns 'content 1'
result[1].Id;      // Returns '2'
result[1].Key;     // Returns 'key 2'
result[1].Content; // Returns 'content 2'
result[0].Id      // Returns '1'
result[0].Key     // Returns 'key 1'
result[0].Content // Returns 'content 1'
result[1].Id      // Returns '2'
result[1].Key     // Returns 'key 2'
result[1].Content // Returns 'content 2'
result[0].id;      // Returns '1'
result[0].key;     // Returns 'key 1'
result[0].content; // Returns 'content 1'
result[1].id;      // Returns '2'
result[1].key;     // Returns 'key 2'
result[1].content; // Returns 'content 2'
result[0].id      # Returns '1'
result[0].key     # Returns 'key 1'
result[0].content # Returns 'content 1'
result[1].id      # Returns '2'
result[1].key     # Returns 'key 2'
result[1].content # Returns 'content 2'
Not available
Update

update()

This method updates the data stored in a record. It accepts the correlationId and the id of the record to be updated as input parameters. In the example below, we change the value of content to ‘new content 2’ for a record with id equal to ‘2’.

let updated = await persistence.update(null, { id: "2", key: "key 2", content: "new content 2" });
var updated = await persistence.UpdateAsync(null, new MyData { Id = "2", Key = "key 2", Content = "new content 2" });
updated, _ := persistence.Update(context.Background(), "123", MyData{Id: "2", Key: "key 2", Content: "new content 2"})
var updated = await persistence.update(null, MyData.from('2', 'key 2', 'new content 2'));
result = persistence.update(None, MyData('2', 'key 2', 'new content 2') )
Not available

Which returns:

result.id;      // Returns '2'
result.key;     // Returns 'key 2'
result.content; // Returns 'new content 2'
result.Id;      // Returns '2'
result.Key;     // Returns 'key 2'
result.Content; // Returns 'new content 2'
result.Id      // Returns '2'
result.Key     // Returns 'key 2'
result.Content // Returns 'new content 2'
result.id;      // Returns '2'
result.key;     // Returns 'key 2'
result.content; // Returns 'new content 2'
result.id      # Returns '2'
result.key     # Returns 'key 2'
result.content # Returns 'new content 2'
Not available

updatePartially()

This method also updates an item, but only the specified fields. It takes the id of the item to be updated and an AnyValueMap object containing the fields to be modified and their updated values as input parameters. The following example shows how to update the content field for a record with id equal to ‘3’.

import { AnyValueMap } from 'pip-services3-commons-nodex';


updated = await persistence.updatePartially(null, "2", AnyValueMap.fromTuples("content", "new content 2 - partially updated"));
using PipServices3.Commons.Data;

result = await persistence.UpdatePartiallyAsync(null, "2", AnyValueMap.FromTuples("content", "new content 2 - partially updated"));
import (
    cdata "github.com/pip-services3-gox/pip-services3-commons-gox/data"
)

updated, _ = persistence.UpdatePartially(context.Background(), "123", "2", cdata.NewAnyValueMapFromTuples(
	"content", "new content 2 - partially updated",
))
import 'package:pip_services3_commons/pip_services3_commons.dart';


updated = await persistence.updatePartially(null, '2',AnyValueMap.fromTuples(['content', 'new content 2 - partially updated']));
from pip_services3_commons.data import AnyValueMap

result = persistence.update_partially(None, '2', AnyValueMap({'content': 'new content 2 - partially updated'}))
Not available

Which returns:

result.id;      // Returns '2'
result.key;     // Returns 'key 2'
result.content; // Returns 'new content 2 - partially updated'
result.Id;      // Returns '2'
result.Key;     // Returns 'key 2'
result.Content; // Returns 'new content 2 - partially updated'
result.Id      // Returns '2'
result.Key     // Returns 'key 2'
result.Content // Returns 'new content 2 - partially updated'
result.id;      // Returns '2'
result.key;     // Returns 'key 2'
result.content; // Returns 'new content 2 - partially updated'
result.id      # Returns '2'
result.key     # Returns 'key 2'
result.content # Returns 'new content 2 - partially updated'
Not available
Delete

deleteById()

We can delete a stored data object by using the delete() method. Here, we need to indicate the correlationId and the id of the object to be deleted. The following example deletes a record with an id equal to ‘1’.

let deleted = await persistence.deleteById(null, "1");
result = await persistence.DeleteByIdAsync(null, "1");
deleted, _ := persistence.DeleteById(context.Background(), "123", "1")
var deleted = await persistence.deleteById(null, '1');
result = persistence.delete_by_id(None, '1')
Not available

Which returns:

result.id;       // Returns '1'
result.key;      // Returns 'key 1'
result.content;  // Returns 'content 1'
result.Id;       // Returns '1'
result.Key;      // Returns 'key 1'
result.Content;  // Returns 'content 1'
result.Id       // Returns '1'
result.Key      // Returns 'key 1'
result.Content  // Returns 'content 1'
result.id;       // Returns '1'
result.key;      // Returns 'key 1'
result.content;  // Returns 'content 1'
result.id       # Returns '1'
result.key      # Returns 'key 1'
result.content  # Returns 'content 1'
Not available

deleteByIds

This method accepts a list containing the ids of the documents to be deleted. The following example shows how to delete the records with ids equal to ‘1’ and ‘2’.

await persistence.deleteByIds(null, ["1", "2"]);
await persistence.DeleteByIdsAsync(null, new string[] { "1", "2" });
_ = persistence.DeleteByIds(context.Background(), "123", []string{"1", "2"})
await persistence.deleteByIds(null, ['1', '2']);
persistence.delete_by_ids(None, ['1', '2'])
Not available
Example

To summarize, we put everything together in one comprehensive example. In it, we first create a data class with a field named id. Then, we create our persistence object, configure it and open the connection. Once we are connected to the database “mydb”, we perform the four CRUD operations and print the results. The code is:

import { AnyValueMap, ConfigParams, FilterParams, IStringIdentifiable, SortParams } from 'pip-services3-commons-nodex';
import { IdentifiableMongoDbPersistence } from 'pip-services3-mongodb-nodex';

export class MyIdentifiableMongoDbPersistence extends IdentifiableMongoDbPersistence<MyData, string> {
    public constructor() {
        super("mydata");
    }
}

export class MyData implements IStringIdentifiable {
    public id: string;
    public key: string;
    public content: string;
}

export function printResult(operationName: string, res: MyData) {
    console.log(`==================== ${operationName} ====================`);
    console.log(`MyData with id: ${res.id}`);
    console.log(`MyData key: ${res.key}`);
    console.log(`MyData content: ${res.content}`);
}


let data1: MyData = { id: "1", key: "key 1", content: "content 1" };

let persistence = new MyIdentifiableMongoDbPersistence();
let config = ConfigParams.fromTuples(
    "connection.host", "localhost",
    "connection.port", 27017,
    "connection.database", "pipdatabase"
);
persistence.configure(config);

await persistence.open(null);
await persistence.clear(null);

// CRUD
// 1 - Create
let result = await persistence.create(null, data1);
printResult("Create", result);

// 2 - Retrieve
let item = await persistence.getOneById("123", "1");
printResult("Get by id", item);

// 3 - Update
let update = await persistence.update(null, { id: "2", key: "key 2", content: "new content 2" });
printResult("Update", update);

// 4 - Delete
let deleted = await persistence.deleteById(null, "1");
printResult("Delete by id", deleted);

await persistence.close(null);

using System;
using System.Runtime.Serialization;

using PipServices3.Commons.Data;
using PipServices3.Commons.Config;
using PipServices3.MongoDb.Persistence;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
using System.Collections.Generic;
using System.Threading.Tasks;

public class MyIdentifiableMongoDbPersistence: IdentifiableMongoDbPersistence<MyData, string>
{
    public MyIdentifiableMongoDbPersistence() : base("mydata") { }
}

[DataContract]
[BsonNoId]
[BsonIgnoreExtraElements]
public class MyData : IStringIdentifiable
{
    [BsonElement("id")]
    [DataMember(Name = "id")]
    public string Id { get; set; }

    [BsonElement("key")]
    [DataMember(Name = "key")]
    public string Key { get; set; }

    [BsonElement("content")]
    [DataMember(Name = "content")]
    public string Content { get; set; }
}

public static void PrintResult(string operationNme, MyData res)
{
    Console.WriteLine($"==================== {operationNme} ====================");
    Console.WriteLine($"MyData Key: {res.Id}");
    Console.WriteLine($"MyData Key: {res.Key}");
    Console.WriteLine($"MyData Key: {res.Content}");
}


var data1 = new MyData { Id = "1", Key = "key 1", Content = "content 1" };

var config = ConfigParams.FromTuples(
    "connection.host", "localhost",
    "connection.port", 27017,
    "connection.database", "pipdatabase"
);

var persistence = new MyIdentifiableMongoDbPersistence();

persistence.Configure(config);

await persistence.OpenAsync("123");
await persistence.ClearAsync("123");

// CRUD
// 1 - Create
var result = await persistence.CreateAsync(null, data1);
PrintResult("Create", result);

// 2 - Retrieve
var item = await persistence.GetOneByIdAsync("123", "1");
PrintResult("Get by id", item);

// 3 - Update
var update = await persistence.UpdateAsync(null, new MyData { Id = "1", Key = "key 2", Content = "new content 2" });
PrintResult("Update", update);

// 4 - Delete
var delete = await persistence.DeleteByIdAsync(null, "1");
PrintResult("Delete by id", delete);

await persistence.CloseAsync(null);

import (
	"fmt"
	"reflect"

	conf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	cdata "github.com/pip-services3-gox/pip-services3-commons-gox/data"
	datpersist "github.com/pip-services3-gox/pip-services3-data-gox/persistence"
	mpersist "github.com/pip-services3-gox/pip-services3-mongodb-gox/persistence"

	mngoptions "go.mongodb.org/mongo-driver/mongo/options"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
)

type MyIdentifiableMongoDbPersistence struct {
	*mpersist.IdentifiableMongoDbPersistence[MyData, string]
}

func NewMyIdentifiableMongoDbPersistencee() *MyIdentifiableMongoDbPersistence {
	c := &MyIdentifiableMongoDbPersistence{}
	c.IdentifiableMongoDbPersistence = mpersist.InheritIdentifiableMongoDbPersistence(c, "mydata")
	return c
}

func PrintResult(operationName string, res MyData) {
	fmt.Println("==================== " + operationName + " ====================")
	fmt.Println("MyData with Id: " + res.Id)
	fmt.Println("MyData with Key: " + res.Key)
	fmt.Println("MyData with Content: " + res.Content)
}


func main() {
	data1 := MyData{Id: "1", Key: "key 1", Content: "content 1"}

	persistence := NewMyIdentifiableMongoDbPersistencee()
	config := conf.NewConfigParamsFromTuples(
		"connection.host", "localhost",
		"connection.port", 27017,
		"connection.database", "pipdatabase",
	)
	persistence.Configure(context.Background(), config)

	_ = persistence.Open(context.Background(), "123")
	_ = persistence.Clear(context.Background(), "123")

	// CRUD
	// 1 - Create
	result, _ := persistence.Create(context.Background(), "123", data1)
	PrintResult("Create", result)

	// 2 - Retrieve
	item, _ := persistence.GetOneById(context.Background(), "123", "1")
	PrintResult("Get by id", item)

	// 3 - Update
	update, _ := persistence.Update(context.Background(), "123", MyData{Id: "1", Key: "key 2", Content: "new content 2"})
	PrintResult("Update", update)

	// 4 - Delete
	delete, _ := persistence.DeleteById(context.Background(), "123", "1")
	PrintResult("Delete by id", delete)

	_ = persistence.Close(context.Background(), "123")
}

import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_mongodb/pip_services3_mongodb.dart';

class MyIdentifiableMongoDbPersistence
    extends IdentifiableMongoDbPersistence<MyData, String> {
  MyIdentifiableMongoDbPersistence() : super('mydata');
}

class MyData implements IStringIdentifiable, ICloneable {
  @override
  String? id;
  String? key;
  String? content;

  MyData();

  MyData.from(this.id, this.key, this.content);

  Map<String, dynamic> toJson() {
    return <String, dynamic>{'id': id, 'key': key, 'content': content};
  }

  void fromJson(Map<String, dynamic> json) {
    id = json['id'];
    key = json['key'];
    content = json['content'];
  }

  @override
  MyData clone() {
    return MyData.from(id, key, content);
  }
}

void printResult(String operationName, MyData res) {
  print('==================== $operationName ====================');
  print('MyData with id: ${res.id}');
  print('MyData key: ${res.key}');
  print('MyData content: ${res.content}');
}

void main(List<String> arguments) async {
  var data1 = MyData.from('1', 'key 1', 'content 1');

  var persistence = MyIdentifiableMongoDbPersistence();
  var config = ConfigParams.fromTuples([
    'connection.host', 'localhost',
    'connection.port', 27017,
    'connection.database', 'pipdatabase'
  ]);
  persistence.configure(config);

  await persistence.open(null);
  await persistence.clear(null);

  // CRUD
  // 1 - Create
  var result = await persistence.create(null, data1);
  printResult('Create', result!);

  // 2 - Retrieve
  var item = await persistence.getOneById('123', '1');
  printResult('Get by id', item!);

  // 3 - Update
  var update = await persistence.update(
      null, MyData.from('1', 'key 1', 'new content 1'));
  printResult('Update', update!);

  // 4 - Delete
  var deleted = await persistence.deleteById(null, '1');
  printResult('Delete by id', deleted!);

  await persistence.close(null);
  await persistence.close(null);
}

from pip_services3_mongodb.persistence import IdentifiableMongoDbPersistence
from pip_services3_commons.config import ConfigParams
import pymongo

class MyIdentifiableMongoDbPersistence(IdentifiableMongoDbPersistence):
    
    def __init__(self):
        super(MyIdentifiableMongoDbPersistence, self).__init__("mydata")
		
persistence = MyIdentifiableMongoDbPersistence()

from pip_services3_commons.data import IStringIdentifiable

class MyData(IStringIdentifiable): 
    def __init__(self, id: str = None, key: str = None, content: str = None): 
        self.id = id 
        self.key = key 
        self.content = content 

data1 = MyData('1', 'key 1', 'content 1') 

config = ConfigParams.from_tuples(
    'connection.host', 'localhost', 
    'connection.port', 27017, 
    'connection.database', 'mydb'
)
persistence.configure(config)

persistence.open("123")
persistence.clear("123")

def print_result(operation_name: str, res: MyData):
    print(f"==================== {operation_name} ====================")
    print(f'MyData with ID: {res.id}')
    print(f'MyData Key: {res.key}')
    print(f'MyData Content: {res.content}')

# CRUD
# 1 - Create
result = persistence.create(None, data1)
print_result('Create', result)

# 2 - Retrieve
item = persistence.get_one_by_id('123','1')
print_result('Get by id', item)

# 3 - Update
update = persistence.update(None, MyData('1', 'key 2', 'new content 2') )
print_result('Update', update)

# 4 - Delete
delete = persistence.delete_by_id(None, "1") 
print_result('Delete by id', delete)

persistence.close(None)
Not available

And the output is:

figure 2

Wrapping up

In this tutorial, we have explored how to create MongoDB persistence components. We saw two different components, namely the MongoDbPersistence and the IdentifiableMongoDbPersistence classes, and how to perform CRUD operations with them. Finally, we saw a comprehensive example for each component.