如何在使用MongoDB Java异步驱动程序插入文档后获取其_id?

4
如何使用MongoDB Java异步驱动程序在插入到MongoDB集合后获取_id
package test;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.allanbank.mongodb.MongoClient;
import com.allanbank.mongodb.MongoClientConfiguration;
import com.allanbank.mongodb.MongoCollection;
import com.allanbank.mongodb.MongoDatabase;
import com.allanbank.mongodb.MongoFactory;
import com.allanbank.mongodb.bson.Document;
import com.allanbank.mongodb.bson.builder.BuilderFactory;
import com.allanbank.mongodb.bson.builder.DocumentBuilder;
import com.allanbank.mongodb.builder.Aggregate;
import com.xxxx.dto.FeedMongoDTO;

/**
* @author abhi
* 
*/
public class MongoTestService {

public static transient Log log = LogFactory.getLog(FeedMongoOperations.class);

private MongoClient mongo;
private MongoDatabase db;
private MongoCollection collection;

public boolean openDbConnection() {
    try {
        MongoClientConfiguration config = new MongoClientConfiguration();
        config.addServer("localhost:27017");
        config.setMaxConnectionCount(10);

        mongo = MongoFactory.createClient(config);

        db = mongo.getDatabase("feedDatabase");

        return true;
    } catch (Exception e) {
        return false;
    }
}

public boolean closeDbConnection() {
    try {
        mongo.close();
        return true;
    } catch (Exception e) {
        return false;
    }
}

public String save(FeedMongoDTO feed, String collectionName) {
    try {

        collection = db.getCollection(collectionName);
        DocumentBuilder b = BuilderFactory.start();
        Document d1 = b.add("url", feed.getUrl()).addLong("mongoTimeStamp", feed.getMongoTimestamp())
                .add("feedJsonArray", feed.getFeedJsonArray()).build();

        collection.insert(d1);

        return d1.get("id").toString();
    } catch (Exception ex) {
        return null;
    }
}

public FeedMongoDTO getFeed(String mongoId, String collectionName) {

    FeedMongoDTO feedMongoDTO = null;

    try {
        return feedMongoDTO;
    } catch (Exception ex) {
        return null;
    }
}
}

其中FeedMongoDTO的结构如下所示:

public class FeedMongoDTO {

    private String id;
    private String url;
    private Long mongoTimeStamp;
    private JSONArray feedJsonArray;

    //  Getters 
    public String getId() {
        return id;
    }

    public String getUrl() {
        return url;
    }

    public Long getMongoTimestamp() {
        return mongoTimeStamp;
    }

    public JSONArray getFeedJsonArray() {
        return feedJsonArray;
    }


    //  Setters 
    public void setId(String id) {
        this.id = id;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void setMongoTimestamp(Long mongoTimestamp) {
        this.mongoTimeStamp = mongoTimestamp;
    }

    public void setFeedJsonArray(JSONArray feedJsonArray) {
        this.feedJsonArray = feedJsonArray;
    }

}

我需要获取_id的值,但是这里d1.get("id").toString()会导致NullPointerException

还有一件事,我很困惑是否我正确地使用了Save()方法。使用通常的mongodb驱动程序更容易。

public String save(FeedMongoDTO feed, String collectionName) {
    try {
        mongoTemplate.save(feed, collectionName);
        return feed.getId();
    } catch (Exception ex) {
        return null;
    } 
} 

感谢您的提前帮助!
Abhilash :)

嗨,orid,感谢您的回复。但是,当我按照您所说的做时,我遇到了一个错误:MongoCollection 类型中的 insert(Durability, DocumentAssignable...) 方法不适用于参数 (Document, Durability)。请更改为 insertAsync()。而当我按照他们所说的做时,我得到了:MongoCollection 类型中的 insertAsync(Durability, DocumentAssignable...) 方法不适用于参数 (Document, Durability)。请更改为 insert() - Abhilash PS
2
我的错误,请将顺序翻转为 collection.insert(d1, Durability.ACK); - Ori Dar
谢谢,orid,它起作用了 :) 但是 System.out.println(d1.get("_id").getValueAsString()); 给出的结果是 ObjectId('5150c3da57199014e86bedc6') - Abhilash PS
1
正如你所发现的那样,如果文档中没有该名称的字段,当你进行插入操作时,驱动程序将在文档中插入一个带有ObjectId的'_id'字段。 - Rob Moore
1
_id是ObjectIdElement类型的一个元素。该元素的值是一个ObjectId,您正在调用它的toString方法,给出了ObjectId('5150c3da57199014e86bedc6')。如果您改为调用toHexString()方法,则会得到5150c3da57199014e86bedc6部分。类似于:d1.get(ObjectIdElement.class,"_id").toHexString(); - Rob Moore
显示剩余3条评论
3个回答

4
如果这是您经常需要做的事情,为什么不自己设置_id呢?您可以通过使用0-arg构造函数轻松构建一个新的ObjectId,并在插入文档之前将其添加到文档中。
ObjectId id = new ObjectId();
documentBuilder.add("_id", id);
collection.insert(documentBuilder);

单独运行一个查询仅为检索id似乎很愚蠢。


0

在我看来,异步Java驱动程序提供了使查询同步的方法,例如使用常规的findOne调用。这对您的需求有意义吗?


嗨,Shelman,实际上,是否有任何简单直接的方法可以像问题中最后一个代码示例中所示那样,在插入后获取_id,其中id是在不进行任何新方法调用的情况下获得的findOne。谢谢 :) - Abhilash PS
你尝试过orid的答案吗?在我看来,你必须使用插入调用的同步版本,因为异步版本无法以你想要的方式返回值。 - shelman
嗨,Shelman,我认为这是一个同步方法,因为有一个具有相同方法签名的insertAsync()方法。 - Abhilash PS
实际上,这是驱动程序中唯一一个文档不是不可变的地方。对于'_id'字段有特殊处理,既可以快速检测到没有文档,又可以确保即使在异步情况下,调用者也可以访问注入的ObjectId。 - Rob Moore

0

在我的异步Node应用程序中创建新名称时,我遇到了这个问题。我想通过ID将用户带到新创建的名称,而不是将用户扔回目录列表。allTwentyQuestions 差不多做对了,但对于Node来说还不太对,这引导我走上了这条路:

addName: function(nameDB, newName, callback){
  nameID = new require('mongodb').ObjectID();
  nameDB.collection('nameList').insert({"_id" : nameID, 'Name' : newName, 'type' : '', 'active' : 'no', 'modifiedDate' : ''}, function(err, result) {
    if (!err) {
        // success
        callback(null, nameID);
    } else {
        // error
        callback('error', err);
    }
  });
}

然后我会从我的应用程序中调用该函数:

mongo.addName(nameDB, newName, function(err, result) {
  if (!err){
    // success
    // direct the user to the proper page with this new ObjectID found in the var 'result'
  } else {
    // error
    console.log('There was an error adding the name: '+ result);
  }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接