class MongoProfileService extends AbstractProfileService<MongoProfile> {

    private MongoClient mongoClient;

    private String usersDatabase = "users";
    private String usersCollection = "users";

    /**
     * <p>Constructor for MongoProfileService.</p>
     */
    public MongoProfileService() {}

    /**
     * <p>Constructor for MongoProfileService.</p>
     *
     * @param mongoClient a {@link MongoClient} object
     */
    public MongoProfileService(final MongoClient mongoClient) {
        this.mongoClient = mongoClient;
    }

    /**
     * <p>Constructor for MongoProfileService.</p>
     *
     * @param mongoClient a {@link MongoClient} object
     * @param attributes a {@link String} object
     */
    public MongoProfileService(final MongoClient mongoClient, final String attributes) {
        this.mongoClient = mongoClient;
        setAttributes(attributes);
    }

    /**
     * <p>Constructor for MongoProfileService.</p>
     *
     * @param mongoClient a {@link MongoClient} object
     * @param attributes a {@link String} object
     * @param passwordEncoder a {@link PasswordEncoder} object
     */
    public MongoProfileService(final MongoClient mongoClient, final String attributes, final PasswordEncoder passwordEncoder) {
        this.mongoClient = mongoClient;
        setAttributes(attributes);
        setPasswordEncoder(passwordEncoder);
    }

    /**
     * <p>Constructor for MongoProfileService.</p>
     *
     * @param mongoClient a {@link MongoClient} object
     * @param passwordEncoder a {@link PasswordEncoder} object
     */
    public MongoProfileService(final MongoClient mongoClient, final PasswordEncoder passwordEncoder) {
        this.mongoClient = mongoClient;
        setPasswordEncoder(passwordEncoder);
    }

    /** {@inheritDoc} */
    @Override
    protected void internalInit(final boolean forceReinit) {
        CommonHelper.assertNotNull("passwordEncoder", getPasswordEncoder());
        CommonHelper.assertNotNull("mongoClient", this.mongoClient);
        CommonHelper.assertNotBlank("usersDatabase", this.usersDatabase);
        CommonHelper.assertNotBlank("usersCollection", this.usersCollection);

        setProfileDefinitionIfUndefined(new CommonProfileDefinition(x -> new MongoProfile()));
        setSerializer(new JsonSerializer(MongoProfile.class));

        super.internalInit(forceReinit);
    }

    /** {@inheritDoc} */
    @Override
    protected void insert(final Map<String, Object> attributes) {<FILL_FUNCTION_BODY>}

    /** {@inheritDoc} */
    @Override
    protected void update(final Map<String, Object> attributes) {
        String id = null;
        val doc = new Document();
        for (val entry : attributes.entrySet()) {
            val name = entry.getKey();
            val value = entry.getValue();
            if (getIdAttribute().equals(name)) {
                id = (String) value;
            } else {
                doc.append(entry.getKey(), entry.getValue());
            }
        }

        CommonHelper.assertNotNull(ID, id);
        logger.debug("Updating id: {} with doc: {}", id, doc);
        getCollection().updateOne(eq(getIdAttribute(), id), new Document("$set", doc));
    }

    /** {@inheritDoc} */
    @Override
    protected void deleteById(final String id) {

        logger.debug("Delete id: {}", id);
        getCollection().deleteOne(eq(getIdAttribute(), id));
    }

    /** {@inheritDoc} */
    @Override
    protected List<Map<String, Object>> read(final List<String> names, final String key, final String value) {

        logger.debug("Reading key / value: {} / {}", key, value);
        List<Map<String, Object>> listAttributes = new ArrayList<>();
        try (val cursor = getCollection().find(eq(key, value)).iterator()) {
            var i = 0;
            while (cursor.hasNext() && i <= 2) {
                val result = cursor.next();
                Map<String, Object> newAttributes = new HashMap<>();
                // filter on names
                for (val entry : result.entrySet()) {
                    val name = entry.getKey();
                    if (names == null || names.contains(name)) {
                        newAttributes.put(name, entry.getValue());
                    }
                }
                listAttributes.add(newAttributes);
                i++;
            }
        }
        logger.debug("Found: {}", listAttributes);

        return listAttributes;
    }

    /**
     * <p>getCollection.</p>
     *
     * @return a {@link MongoCollection} object
     */
    protected MongoCollection<Document> getCollection() {
        val db = mongoClient.getDatabase(usersDatabase);
        return db.getCollection(usersCollection);
    }
}

        val doc = new Document();
        for (val entry : attributes.entrySet()) {
            doc.append(entry.getKey(), entry.getValue());
        }

        logger.debug("Insert doc: {}", doc);
        getCollection().insertOne(doc);
    
<methods>public non-sealed void <init>() ,public void create(org.pac4j.mongo.profile.MongoProfile, java.lang.String) ,public org.pac4j.mongo.profile.MongoProfile findById(java.lang.String) ,public org.pac4j.mongo.profile.MongoProfile findByLinkedId(java.lang.String) ,public void remove(org.pac4j.mongo.profile.MongoProfile) ,public void removeById(java.lang.String) ,public void update(org.pac4j.mongo.profile.MongoProfile, java.lang.String) ,public Optional<org.pac4j.core.credentials.Credentials> validate(CallContext, org.pac4j.core.credentials.Credentials) <variables>public static final java.lang.String ID,public static final java.lang.String LINKEDID,public static final java.lang.String SERIALIZED_PROFILE,protected java.lang.String[] attributeNames,private java.lang.String attributes,private java.lang.String idAttribute,protected final org.slf4j.Logger logger,private java.lang.String passwordAttribute,private org.pac4j.core.credentials.password.PasswordEncoder passwordEncoder,private org.pac4j.core.util.serializer.Serializer serializer,private java.lang.String usernameAttribute