Example usage for com.mongodb DBCollection findAndModify

List of usage examples for com.mongodb DBCollection findAndModify

Introduction

In this page you can find the example usage for com.mongodb DBCollection findAndModify.

Prototype

@Nullable
public DBObject findAndModify(@Nullable final DBObject query, @Nullable final DBObject fields,
        @Nullable final DBObject sort, final boolean remove, @Nullable final DBObject update,
        final boolean returnNew, final boolean upsert) 

Source Link

Document

Atomically modify and return a single document.

Usage

From source file:com.softinstigate.restheart.db.CollectionDAO.java

License:Open Source License

/**
 * Upsert the collection properties.//w w  w.j  av a 2 s .c o  m
 *
 * @param dbName the database name of the collection
 * @param collName the collection name
 * @param content the new collection properties
 * @param etag the entity tag. must match to allow actual write (otherwise
 * http error code is returned)
 * @param updating true if updating existing document
 * @param patching true if use patch semantic (update only specified fields)
 * @return the HttpStatus code to set in the http response
 */
public static int upsertCollection(String dbName, String collName, DBObject content, ObjectId etag,
        boolean updating, boolean patching) {
    DB db = DBDAO.getDB(dbName);

    DBCollection coll = db.getCollection(collName);

    if (patching && !updating) {
        return HttpStatus.SC_NOT_FOUND;
    }

    if (updating) {
        if (etag == null) {
            return HttpStatus.SC_CONFLICT;
        }

        BasicDBObject idAndEtagQuery = new BasicDBObject("_id", "_properties");
        idAndEtagQuery.append("_etag", etag);

        if (coll.count(idAndEtagQuery) < 1) {
            return HttpStatus.SC_PRECONDITION_FAILED;
        }
    }

    ObjectId timestamp = new ObjectId();
    Instant now = Instant.ofEpochSecond(timestamp.getTimestamp());

    if (content == null) {
        content = new BasicDBObject();
    }

    content.removeField("_id"); // make sure we don't change this field

    if (updating) {
        content.removeField("_crated_on"); // don't allow to update this field
        content.put("_etag", timestamp);
    } else {
        content.put("_id", "_properties");
        content.put("_created_on", now.toString());
        content.put("_etag", timestamp);
    }

    if (patching) {
        coll.update(PROPS_QUERY, new BasicDBObject("$set", content), true, false);
        return HttpStatus.SC_OK;
    } else {
        // we use findAndModify to get the @created_on field value from the existing properties document
        // we need to put this field back using a second update 
        // it is not possible in a single update even using $setOnInsert update operator
        // in this case we need to provide the other data using $set operator and this makes it a partial update (patch semantic) 

        DBObject old = coll.findAndModify(PROPS_QUERY, fieldsToReturn, null, false, content, false, true);

        if (old != null) {
            Object oldTimestamp = old.get("_created_on");

            if (oldTimestamp == null) {
                oldTimestamp = now.toString();
                logger.warn("properties of collection {} had no @created_on field. set to now",
                        coll.getFullName());
            }

            // need to readd the @created_on field 
            BasicDBObject createdContet = new BasicDBObject("_created_on", "" + oldTimestamp);
            createdContet.markAsPartialObject();
            coll.update(PROPS_QUERY, new BasicDBObject("$set", createdContet), true, false);

            return HttpStatus.SC_OK;
        } else {
            // need to readd the @created_on field 
            BasicDBObject createdContet = new BasicDBObject("_created_on", now.toString());
            createdContet.markAsPartialObject();
            coll.update(PROPS_QUERY, new BasicDBObject("$set", createdContet), true, false);

            initDefaultIndexes(coll);

            return HttpStatus.SC_CREATED;
        }
    }
}

From source file:com.softinstigate.restheart.db.DBDAO.java

License:Open Source License

/**
 *
 * @param dbName//  w w  w  . jav a  2  s .  co m
 * @param content
 * @param etag
 * @param patching
 * @return
 */
public static int upsertDB(String dbName, DBObject content, ObjectId etag, boolean patching) {
    DB db = client.getDB(dbName);

    boolean existing = db.getCollectionNames().size() > 0;

    if (patching && !existing) {
        return HttpStatus.SC_NOT_FOUND;
    }

    DBCollection coll = db.getCollection("_properties");

    // check the etag
    if (db.collectionExists("_properties")) {
        if (etag == null) {
            return HttpStatus.SC_CONFLICT;
        }

        BasicDBObject idAndEtagQuery = new BasicDBObject("_id", "_properties");
        idAndEtagQuery.append("_etag", etag);

        if (coll.count(idAndEtagQuery) < 1) {
            return HttpStatus.SC_PRECONDITION_FAILED;
        }
    }

    // apply new values
    ObjectId timestamp = new ObjectId();
    Instant now = Instant.ofEpochSecond(timestamp.getTimestamp());

    if (content == null) {
        content = new BasicDBObject();
    }

    content.put("_etag", timestamp);
    content.removeField("_created_on"); // make sure we don't change this field
    content.removeField("_id"); // make sure we don't change this field

    if (patching) {
        coll.update(METADATA_QUERY, new BasicDBObject("$set", content), true, false);

        return HttpStatus.SC_OK;
    } else {
        // we use findAndModify to get the @created_on field value from the existing document
        // we need to put this field back using a second update 
        // it is not possible in a single update even using $setOnInsert update operator
        // in this case we need to provide the other data using $set operator and this makes it a partial update (patch semantic) 
        DBObject old = coll.findAndModify(METADATA_QUERY, fieldsToReturn, null, false, content, false, true);

        if (old != null) {
            Object oldTimestamp = old.get("_created_on");

            if (oldTimestamp == null) {
                oldTimestamp = now.toString();
                logger.warn("properties of collection {} had no @created_on field. set to now",
                        coll.getFullName());
            }

            // need to readd the @created_on field 
            BasicDBObject createdContet = new BasicDBObject("_created_on", "" + oldTimestamp);
            createdContet.markAsPartialObject();
            coll.update(METADATA_QUERY, new BasicDBObject("$set", createdContet), true, false);

            return HttpStatus.SC_OK;
        } else {
            // need to readd the @created_on field 
            BasicDBObject createdContet = new BasicDBObject("_created_on", now.toString());
            createdContet.markAsPartialObject();
            coll.update(METADATA_QUERY, new BasicDBObject("$set", createdContet), true, false);

            return HttpStatus.SC_CREATED;
        }
    }
}

From source file:com.softinstigate.restheart.db.DocumentDAO.java

License:Open Source License

/**
 *
 *
 * @param dbName/*w w  w .java  2  s . c om*/
 * @param collName
 * @param documentId
 * @param content
 * @param requestEtag
 * @param patching
 * @return the HttpStatus code to retrun
 */
public static int upsertDocument(String dbName, String collName, String documentId, DBObject content,
        ObjectId requestEtag, boolean patching) {
    DB db = DBDAO.getDB(dbName);

    DBCollection coll = db.getCollection(collName);

    ObjectId timestamp = new ObjectId();
    Instant now = Instant.ofEpochSecond(timestamp.getTimestamp());

    if (content == null) {
        content = new BasicDBObject();
    }

    content.put("_etag", timestamp);

    BasicDBObject idQuery = new BasicDBObject("_id", getId(documentId));

    if (patching) {
        content.removeField("_created_on"); // make sure we don't change this field

        DBObject oldDocument = coll.findAndModify(idQuery, null, null, false,
                new BasicDBObject("$set", content), false, false);

        if (oldDocument == null) {
            return HttpStatus.SC_NOT_FOUND;
        } else {
            // check the old etag (in case restore the old document version)
            return optimisticCheckEtag(coll, oldDocument, requestEtag, HttpStatus.SC_OK);
        }
    } else {
        content.put("_created_on", now.toString()); // let's assume this is an insert. in case we'll set it back with a second update

        // we use findAndModify to get the @created_on field value from the existing document
        // in case this is an update well need to put it back using a second update 
        // it is not possible to do it with a single update
        // (even using $setOnInsert update because we'll need to use the $set operator for other data and this would make it a partial update (patch semantic) 
        DBObject oldDocument = coll.findAndModify(idQuery, null, null, false, content, false, true);

        if (oldDocument != null) { // upsert
            Object oldTimestamp = oldDocument.get("_created_on");

            if (oldTimestamp == null) {
                oldTimestamp = now.toString();
                logger.warn("properties of document /{}/{}/{} had no @created_on field. set to now", dbName,
                        collName, documentId);
            }

            // need to readd the @created_on field 
            BasicDBObject created = new BasicDBObject("_created_on", "" + oldTimestamp);
            created.markAsPartialObject();
            coll.update(idQuery, new BasicDBObject("$set", created), true, false);

            // check the old etag (in case restore the old document version)
            return optimisticCheckEtag(coll, oldDocument, requestEtag, HttpStatus.SC_OK);
        } else { // insert
            return HttpStatus.SC_CREATED;
        }
    }
}

From source file:com.softinstigate.restheart.db.DocumentDAO.java

License:Open Source License

/**
 *
 *
 * @param exchange/*from  ww w.j a v  a 2 s  .  com*/
 * @param dbName
 * @param collName
 * @param content
 * @param requestEtag
 * @return the HttpStatus code to retrun
 */
public static int upsertDocumentPost(HttpServerExchange exchange, String dbName, String collName,
        DBObject content, ObjectId requestEtag) {
    DB db = DBDAO.getDB(dbName);

    DBCollection coll = db.getCollection(collName);

    ObjectId timestamp = new ObjectId();
    Instant now = Instant.ofEpochSecond(timestamp.getTimestamp());

    if (content == null) {
        content = new BasicDBObject();
    }

    content.put("_etag", timestamp);
    content.put("_created_on", now.toString()); // make sure we don't change this field

    Object _id = content.get("_id");
    content.removeField("_id");

    if (_id == null) {
        ObjectId id = new ObjectId();
        content.put("_id", id);

        coll.insert(content);

        exchange.getResponseHeaders().add(HttpString.tryFromString("Location"),
                getReferenceLink(exchange.getRequestURL(), id.toString()).toString());

        return HttpStatus.SC_CREATED;
    }

    BasicDBObject idQuery = new BasicDBObject("_id", getId("" + _id));

    // we use findAndModify to get the @created_on field value from the existing document
    // we need to put this field back using a second update 
    // it is not possible in a single update even using $setOnInsert update operator
    // in this case we need to provide the other data using $set operator and this makes it a partial update (patch semantic) 
    DBObject oldDocument = coll.findAndModify(idQuery, null, null, false, content, false, true);

    if (oldDocument != null) { // upsert
        Object oldTimestamp = oldDocument.get("_created_on");

        if (oldTimestamp == null) {
            oldTimestamp = now.toString();
            logger.warn("properties of document /{}/{}/{} had no @created_on field. set to now", dbName,
                    collName, _id.toString());
        }

        // need to readd the @created_on field 
        BasicDBObject createdContet = new BasicDBObject("_created_on", "" + oldTimestamp);
        createdContet.markAsPartialObject();
        coll.update(idQuery, new BasicDBObject("$set", createdContet), true, false);

        // check the old etag (in case restore the old document version)
        return optimisticCheckEtag(coll, oldDocument, requestEtag, HttpStatus.SC_OK);
    } else { // insert
        return HttpStatus.SC_CREATED;
    }
}

From source file:com.softinstigate.restheart.db.DocumentDAO.java

License:Open Source License

/**
 *
 * @param dbName//  ww w  . ja  va2  s.co  m
 * @param collName
 * @param documentId
 * @param requestEtag
 * @return
 */
public static int deleteDocument(String dbName, String collName, String documentId, ObjectId requestEtag) {
    DB db = DBDAO.getDB(dbName);

    DBCollection coll = db.getCollection(collName);

    BasicDBObject idQuery = new BasicDBObject("_id", getId(documentId));

    DBObject oldDocument = coll.findAndModify(idQuery, null, null, true, null, false, false);

    if (oldDocument == null) {
        return HttpStatus.SC_NOT_FOUND;
    } else {
        // check the old etag (in case restore the old document version)
        return optimisticCheckEtag(coll, oldDocument, requestEtag, HttpStatus.SC_NO_CONTENT);
    }
}

From source file:com.streamreduce.storm.MongoClient.java

License:Apache License

/**
 * Updates the collection that tracks the last processed event date of the spouts.
 *
 * @param spoutName              name of the spout
 * @param lastProcessedEventDate last processed event date
 *///  w w w .  jav a  2s  .c o m
public void updateLastProcessedEventDate(String spoutName, long lastProcessedEventDate) {
    DB connectionsDb = getDB("nodeablemsgdb");
    DBCollection eventCollection = connectionsDb.getCollection("spoutLastProcessedDate");
    BasicDBObject query = new BasicDBObject();
    query.put("spoutName", spoutName);
    BasicDBObject update = new BasicDBObject();
    update.put("spoutName", spoutName);
    update.put("lastProcessedEventDate", lastProcessedEventDate);
    eventCollection.findAndModify(query, null, null, false, update, false, true);
}

From source file:org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStore.java

License:Apache License

@SuppressWarnings("unchecked")
@CheckForNull// www .  j ava2 s .c  o  m
private <T extends Document> T findAndModify(Collection<T> collection, UpdateOp updateOp, boolean upsert,
        boolean checkConditions) {
    DBCollection dbCollection = getDBCollection(collection);
    // make sure we don't modify the original updateOp
    updateOp = updateOp.copy();
    DBObject update = createUpdate(updateOp, false);

    Lock lock = null;
    if (collection == Collection.NODES) {
        lock = nodeLocks.acquire(updateOp.getId());
    }
    final Stopwatch watch = startWatch();
    boolean newEntry = false;
    try {
        // get modCount of cached document
        Long modCount = null;
        T cachedDoc = null;
        if (collection == Collection.NODES) {
            cachedDoc = (T) nodesCache.getIfPresent(updateOp.getId());
            if (cachedDoc != null) {
                modCount = cachedDoc.getModCount();
            }
        }

        // perform a conditional update with limited result
        // if we have a matching modCount
        if (modCount != null) {

            QueryBuilder query = createQueryForUpdate(updateOp.getId(), updateOp.getConditions());
            query.and(Document.MOD_COUNT).is(modCount);

            WriteResult result = dbCollection.update(query.get(), update);
            if (result.getN() > 0) {
                // success, update cached document
                if (collection == Collection.NODES) {
                    NodeDocument newDoc = (NodeDocument) applyChanges(collection, cachedDoc, updateOp);
                    nodesCache.put(newDoc);
                }
                // return previously cached document
                return cachedDoc;
            }
        }

        // conditional update failed or not possible
        // perform operation and get complete document
        QueryBuilder query = createQueryForUpdate(updateOp.getId(), updateOp.getConditions());
        DBObject oldNode = dbCollection.findAndModify(query.get(), null, null /*sort*/, false /*remove*/,
                update, false /*returnNew*/, upsert);

        if (oldNode == null) {
            newEntry = true;
        }

        if (checkConditions && oldNode == null) {
            return null;
        }
        T oldDoc = convertFromDBObject(collection, oldNode);
        if (oldDoc != null) {
            if (collection == Collection.NODES) {
                NodeDocument newDoc = (NodeDocument) applyChanges(collection, oldDoc, updateOp);
                nodesCache.put(newDoc);
                updateLocalChanges(newDoc);
            }
            oldDoc.seal();
        } else if (upsert) {
            if (collection == Collection.NODES) {
                NodeDocument doc = (NodeDocument) collection.newDocument(this);
                UpdateUtils.applyChanges(doc, updateOp);
                nodesCache.putIfAbsent(doc);
                updateLocalChanges(doc);
            }
        } else {
            // updateOp without conditions and not an upsert
            // this means the document does not exist
        }
        return oldDoc;
    } catch (Exception e) {
        throw DocumentStoreException.convert(e);
    } finally {
        if (lock != null) {
            lock.unlock();
        }
        stats.doneFindAndModify(watch.elapsed(TimeUnit.NANOSECONDS), collection, updateOp.getId(), newEntry,
                true, 0);
    }
}

From source file:org.einherjer.week2.samples.FindAndModifySample.java

License:Apache License

private static int getRange(String id, int range, DBCollection collection) {
    DBObject doc = collection.findAndModify(new BasicDBObject("_id", id), null, null, false,
            new BasicDBObject("$inc", new BasicDBObject("counter", range)), true, true);
    return (Integer) doc.get("counter") - range + 1;
}

From source file:org.hibernate.ogm.datastore.mongodb.MongoDBDialect.java

License:LGPL

@Override
public Number nextValue(NextValueRequest request) {
    DBCollection currentCollection = getCollection(request.getKey().getTable());
    DBObject query = this.prepareIdObject(request.getKey());
    //all columns should match to find the value

    String valueColumnName = request.getKey().getMetadata().getValueColumnName();

    BasicDBObject update = new BasicDBObject();
    //FIXME how to set the initialValue if the document is not present? It seems the inc value is used as initial new value
    Integer incrementObject = Integer.valueOf(request.getIncrement());
    this.addSubQuery("$inc", update, valueColumnName, incrementObject);
    DBObject result = currentCollection.findAndModify(query, null, null, false, update, false, true);
    Object idFromDB;/*from  ww w  .  j av a2s .  com*/
    idFromDB = result == null ? null : result.get(valueColumnName);
    if (idFromDB == null) {
        //not inserted yet so we need to add initial value to increment to have the right next value in the DB
        //FIXME that means there is a small hole as when there was not value in the DB, we do add initial value in a non atomic way
        BasicDBObject updateForInitial = new BasicDBObject();
        this.addSubQuery("$inc", updateForInitial, valueColumnName, request.getInitialValue());
        currentCollection.findAndModify(query, null, null, false, updateForInitial, false, true);
        idFromDB = request.getInitialValue(); //first time we ask this value
    } else {
        idFromDB = result.get(valueColumnName);
    }
    if (idFromDB.getClass().equals(Integer.class) || idFromDB.getClass().equals(Long.class)) {
        Number id = (Number) idFromDB;
        //idFromDB is the one used and the BD contains the next available value to use
        return id;
    } else {
        throw new HibernateException("Cannot increment a non numeric field");
    }
}

From source file:org.hibernate.ogm.dialect.mongodb.MongoDBDialect.java

License:Open Source License

@Override
public void nextValue(RowKey key, IntegralDataTypeHolder value, int increment, int initialValue) {
    DBCollection currentCollection = this.currentDB.getCollection(key.getTable());
    DBObject query = new BasicDBObject();
    int size = key.getColumnNames().length;
    //all columns should match to find the value
    for (int index = 0; index < size; index++) {
        query.put(key.getColumnNames()[index], key.getColumnValues()[index]);
    }/* ww w .j  av  a  2s .c o  m*/
    BasicDBObject update = new BasicDBObject();
    //FIXME should "value" be hardcoded?
    //FIXME how to set the initialValue if the document is not present? It seems the inc value is used as initial new value
    Integer incrementObject = increment == 1 ? ONE : Integer.valueOf(increment);
    this.addSubQuery("$inc", update, SEQUENCE_VALUE, incrementObject);
    DBObject result = currentCollection.findAndModify(query, null, null, false, update, false, true);
    Object idFromDB;
    idFromDB = result == null ? null : result.get(SEQUENCE_VALUE);
    if (idFromDB == null) {
        //not inserted yet so we need to add initial value to increment to have the right next value in the DB
        //FIXME that means there is a small hole as when there was not value in the DB, we do add initial value in a non atomic way
        BasicDBObject updateForInitial = new BasicDBObject();
        this.addSubQuery("$inc", updateForInitial, SEQUENCE_VALUE, initialValue);
        currentCollection.findAndModify(query, null, null, false, updateForInitial, false, true);
        idFromDB = initialValue; //first time we ask this value
    } else {
        idFromDB = result.get(SEQUENCE_VALUE);
    }
    if (idFromDB.getClass().equals(Integer.class) || idFromDB.getClass().equals(Long.class)) {
        Number id = (Number) idFromDB;
        //idFromDB is the one used and the BD contains the next available value to use
        value.initialize(id.longValue());
    } else {
        throw new HibernateException("Cannot increment a non numeric field");
    }
}