Skip to content

Commit 1c03583

Browse files
authored
[NOID] Fixes #3203: apoc.mongo dependencies are outdated with current mongodb (#3897) (#3979)
* [NOID] Fixes #3203: apoc.mongo dependencies are outdated with current mongodb (#3897) * [NOID] fix compile error and code formatting * [NOID] code formatting
1 parent 490adf9 commit 1c03583

File tree

10 files changed

+159
-96
lines changed

10 files changed

+159
-96
lines changed

docs/asciidoc/modules/ROOT/partials/mongodb-dependencies.adoc

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,3 @@ The Mongo procedures have dependencies on a client library that is not included
33
This dependency is included in https://github.com/neo4j-contrib/neo4j-apoc-procedures/releases/download/{apoc-release}/apoc-mongodb-dependencies-{apoc-release}.jar[apoc-mongodb-dependencies-{apoc-release}.jar^], which can be downloaded from the https://github.com/neo4j-contrib/neo4j-apoc-procedures/releases/tag/{apoc-release}[releases page^].
44
Once that file is downloaded, it should be placed in the `plugins` directory and the Neo4j Server restarted.
55

6-
7-
8-
Alternatively, you could copy these jars into the plugins directory:
9-
10-
* bson-3.4.2.jar
11-
* mongo-java-driver-3.4.2.jar,
12-
* mongodb-driver-3.4.2.jar
13-
* mongodb-driver-core-3.4.2.jar
14-
15-
You should be able to get them from the following links:
16-
17-
- https://mvnrepository.com/artifact/org.mongodb/mongo-java-driver/3.4.2[mongo-java-driver]
18-
- https://mvnrepository.com/artifact/org.mongodb/mongodb-driver/3.4.2[mongodb-driver]
19-
- https://mvnrepository.com/artifact/org.mongodb/mongodb-driver-core/3.4.2[mongodb-driver-core]
20-
- https://mvnrepository.com/artifact/org.mongodb/bson/3.4.2[BSON]

extra-dependencies/mongodb/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jar {
1919
}
2020

2121
dependencies {
22-
implementation 'org.mongodb:mongodb-driver:3.2.2', {
22+
implementation group: 'org.mongodb', name: 'mongodb-driver-sync', version: '4.11.1', {
2323
exclude group: 'io.netty'
2424
}
2525
}

full/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,10 @@ dependencies {
110110
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-databind'
111111
}
112112

113-
compileOnly 'org.mongodb:mongodb-driver:3.2.2', {
113+
compileOnly group: 'org.mongodb', name: 'mongodb-driver-sync', version: '4.11.1', {
114114
exclude group: 'io.netty'
115115
}
116-
testImplementation 'org.mongodb:mongodb-driver:3.2.2', {
116+
testImplementation group: 'org.mongodb', name: 'mongodb-driver-sync', version: '4.11.1', {
117117
exclude group: 'io.netty'
118118
}
119119

full/src/main/java/apoc/mongodb/MongoDBColl.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323
import apoc.util.Util;
2424
import com.fasterxml.jackson.databind.DeserializationFeature;
2525
import com.fasterxml.jackson.databind.ObjectMapper;
26-
import com.mongodb.MongoClient;
27-
import com.mongodb.MongoClientURI;
28-
import com.mongodb.MongoCommandException;
26+
import com.mongodb.ConnectionString;
2927
import com.mongodb.client.FindIterable;
28+
import com.mongodb.client.MongoClient;
29+
import com.mongodb.client.MongoClients;
3030
import com.mongodb.client.MongoCollection;
3131
import com.mongodb.client.MongoDatabase;
3232
import com.mongodb.client.MongoIterable;
@@ -73,8 +73,7 @@ class MongoDBColl implements MongoDbCollInterface {
7373
public static final String ERROR_MESSAGE = "The connection string must have %s name";
7474

7575
private MongoDBColl(String url, String db, String coll) {
76-
MongoClientURI connectionString = new MongoClientURI(url);
77-
mongoClient = new MongoClient(connectionString);
76+
mongoClient = MongoClients.create(url);
7877
database = mongoClient.getDatabase(db);
7978
collection = database.getCollection(coll);
8079
}
@@ -100,13 +99,12 @@ public MongoDBColl(
10099
/**
101100
*
102101
* @param uri the string Uri to convert in connectionString
103-
* @see MongoClientURI
104102
* @param conf the configuration
105103
* @see MongoDbConfig
106104
*/
107105
public MongoDBColl(String uri, MongoDbConfig conf) {
108106

109-
MongoClientURI connectionString = new MongoClientURI(uri);
107+
ConnectionString connectionString = new ConnectionString(uri);
110108

111109
if (connectionString.getDatabase() == null) {
112110
throw new RuntimeException(format(ERROR_MESSAGE, "db"));
@@ -124,13 +122,13 @@ public MongoDBColl(String uri, MongoDbConfig conf) {
124122
collectionName = collectionFromUri;
125123
}
126124

127-
mongoClient = new MongoClient(connectionString);
125+
mongoClient = MongoClients.create(connectionString);
128126
database = mongoClient.getDatabase(connectionString.getDatabase());
129127

130128
try {
131129
// check if correctly authenticated
132130
database.runCommand(new Document("listCollections", 1));
133-
} catch (MongoCommandException e) {
131+
} catch (Exception e) {
134132
mongoClient.close();
135133
throw new RuntimeException(e);
136134
}
@@ -272,12 +270,12 @@ public Stream<Map<String, Object>> all(Map<String, Object> query, Long skip, Lon
272270

273271
@Override
274272
public long count(Map<String, Object> query) {
275-
return query == null ? collection.count() : collection.count(new Document(query));
273+
return query == null ? collection.countDocuments() : collection.countDocuments(new Document(query));
276274
}
277275

278276
@Override
279277
public long count(Document query) {
280-
return collection.count(query);
278+
return collection.countDocuments(query);
281279
}
282280

283281
@Override

full/src/main/java/apoc/mongodb/MongoDBUtils.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,18 @@ protected static Document getDocument(Object query) {
3434
if (query == null) {
3535
return new Document();
3636
}
37-
return Document.parse(query instanceof String ? (String) query : JsonUtil.writeValueAsString(query));
37+
String json = query instanceof String ? (String) query : JsonUtil.writeValueAsString(query);
38+
39+
json = adaptLegacyDocuments(json);
40+
41+
return Document.parse(json);
42+
}
43+
44+
/**
45+
* In case someone use an old notation, e.g. {`$binary`: $bytes, `$subType`: '00'}
46+
*/
47+
private static String adaptLegacyDocuments(String json) {
48+
return json.replace("'$subType'", "'$type'").replace("\"$subType\"", "\"$type\"");
3849
}
3950

4051
protected static List<Document> getDocuments(List<Map<String, Object>> pipeline) {

full/src/test/java/apoc/mongodb/MongoDBTest.java

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import apoc.util.MapUtil;
2929
import apoc.util.TestUtil;
3030
import apoc.util.UrlResolver;
31-
import com.mongodb.MongoClient;
31+
import com.mongodb.client.MongoClient;
32+
import com.mongodb.client.MongoClients;
33+
import java.text.ParseException;
3234
import java.time.LocalDateTime;
3335
import java.time.ZoneId;
3436
import java.util.Arrays;
@@ -49,17 +51,18 @@
4951
* @since 30.06.16
5052
*/
5153
public class MongoDBTest extends MongoTestBase {
52-
private static Map<String, Object> params;
5354

5455
private static String HOST = null;
5556

5657
@BeforeClass
5758
public static void setUp() throws Exception {
58-
createContainer(false);
59-
MongoClient mongoClient =
60-
new MongoClient(mongo.getContainerIpAddress(), mongo.getMappedPort(MONGO_DEFAULT_PORT));
59+
beforeClassCommon(MongoVersion.LATEST);
60+
}
61+
62+
static void beforeClassCommon(MongoVersion mongoVersion) throws ParseException {
63+
createContainer(false, mongoVersion);
6164
HOST = String.format("mongodb://%s:%s", mongo.getContainerIpAddress(), mongo.getMappedPort(MONGO_DEFAULT_PORT));
62-
params = map("host", HOST, "db", "test", "collection", "test");
65+
MongoClient mongoClient = MongoClients.create(HOST);
6366

6467
fillDb(mongoClient);
6568

@@ -149,16 +152,7 @@ public void testGetByObjectId() throws Exception {
149152
r -> {
150153
Map doc = (Map) r.get("value");
151154
assertTrue(doc.get("_id") instanceof Map);
152-
assertEquals(
153-
Set.of(
154-
"date",
155-
"machineIdentifier",
156-
"processIdentifier",
157-
"counter",
158-
"time",
159-
"timestamp",
160-
"timeSecond"),
161-
((Map<String, Object>) doc.get("_id")).keySet());
155+
assertEquals(Set.of("date", "timestamp"), ((Map<String, Object>) doc.get("_id")).keySet());
162156
assertEquals("Sherlock", doc.get("name"));
163157
assertEquals(25L, doc.get("age"));
164158
assertEquals(refsIds, doc.get("bought"));
@@ -177,16 +171,7 @@ public void testGetByObjectIdWithCustomIdFieldName() throws Exception {
177171
r -> {
178172
Map doc = (Map) r.get("value");
179173
assertTrue(doc.get("_id") instanceof Map);
180-
assertEquals(
181-
Set.of(
182-
"date",
183-
"machineIdentifier",
184-
"processIdentifier",
185-
"counter",
186-
"time",
187-
"timestamp",
188-
"timeSecond"),
189-
((Map<String, Object>) doc.get("_id")).keySet());
174+
assertEquals(Set.of("date", "timestamp"), ((Map<String, Object>) doc.get("_id")).keySet());
190175
assertEquals(40L, doc.get("age"));
191176
assertEquals(refsIds, doc.get("bought"));
192177
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package apoc.mongodb;
2+
3+
import org.junit.BeforeClass;
4+
5+
/**
6+
* To check that, with the latest mongodb java driver,
7+
* the {@link MongoDBTest} works correctly with mongoDB 4
8+
*/
9+
public class MongoDBVersion4Test extends MongoDBTest {
10+
11+
@BeforeClass
12+
public static void setUp() throws Exception {
13+
MongoDBTest.beforeClassCommon(MongoVersion.FOUR);
14+
}
15+
}

full/src/test/java/apoc/mongodb/MongoTest.java

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828

2929
import apoc.graph.Graphs;
3030
import apoc.util.TestUtil;
31-
import com.mongodb.MongoClient;
32-
import com.mongodb.MongoClientURI;
31+
import com.mongodb.client.MongoClient;
32+
import com.mongodb.client.MongoClients;
3333
import com.mongodb.client.MongoCollection;
3434
import com.mongodb.client.MongoDatabase;
3535
import java.time.Instant;
@@ -39,6 +39,7 @@
3939
import java.util.Date;
4040
import java.util.Map;
4141
import java.util.Set;
42+
import java.util.function.Consumer;
4243
import org.apache.commons.lang3.time.DateUtils;
4344
import org.bson.BsonDouble;
4445
import org.bson.BsonInt32;
@@ -54,7 +55,6 @@
5455
import org.bson.types.ObjectId;
5556
import org.bson.types.Symbol;
5657
import org.junit.BeforeClass;
57-
import org.junit.Ignore;
5858
import org.junit.Test;
5959
import org.neo4j.graphdb.QueryExecutionException;
6060
import org.neo4j.graphdb.ResourceIterator;
@@ -74,21 +74,25 @@ public class MongoTest extends MongoTestBase {
7474

7575
@BeforeClass
7676
public static void setUp() throws Exception {
77-
createContainer(true);
77+
beforeClassCommon(MongoVersion.LATEST);
78+
}
79+
80+
static void beforeClassCommon(MongoVersion mongoVersion) throws Exception {
81+
createContainer(true, mongoVersion);
82+
7883
TestUtil.registerProcedure(db, Mongo.class, Graphs.class);
7984

8085
// readWrite user creation
8186
mongo.execInContainer(
82-
"mongo",
87+
mongoVersion.shell,
8388
"admin",
8489
"--eval",
8590
"db.auth('admin', 'pass'); db.createUser({user: 'user', pwd: 'secret',roles: [{role: 'readWrite', db: 'test'}]});");
8691

8792
final String host = mongo.getHost();
8893
final Integer port = mongo.getMappedPort(MONGO_DEFAULT_PORT);
8994
final String format = String.format("mongodb://admin:pass@%s:%s", host, port);
90-
MongoClientURI clientURI = new MongoClientURI(format);
91-
try (MongoClient mongoClient = new MongoClient(clientURI)) {
95+
try (MongoClient mongoClient = MongoClients.create(format)) {
9296
String uriPrefix = String.format(
9397
"mongodb://admin:pass@%s:%s",
9498
mongo.getContainerIpAddress(), mongo.getMappedPort(MONGO_DEFAULT_PORT));
@@ -304,6 +308,63 @@ public void objectIdAsString() {
304308
});
305309
}
306310

311+
@Test
312+
public void countWithStringOrMapBinaryQuery() {
313+
String bytesEncoded = Base64.getEncoder().encodeToString("fooBar".getBytes());
314+
Map<String, Object> params = map("uri", PERSON_URI);
315+
Consumer<Map<String, Object>> consumer = r -> assertEquals(2L, r.get("value"));
316+
317+
// string queries (with respectively double and single quotes)
318+
testCall(
319+
db,
320+
String.format(
321+
"CALL apoc.mongo.count($uri, \"{'binary':{'$binary':'%s','$type':'00'}}\")", bytesEncoded),
322+
params,
323+
consumer);
324+
325+
testCall(
326+
db,
327+
String.format(
328+
"CALL apoc.mongo.count($uri, '{\"binary\":{\"$binary\":\"%s\",\"$type\":\"00\"}}')",
329+
bytesEncoded),
330+
params,
331+
consumer);
332+
333+
// map query
334+
testCall(
335+
db,
336+
String.format("CALL apoc.mongo.count($uri, {binary: {`$binary`: '%s', `$type`: '00'}})", bytesEncoded),
337+
params,
338+
consumer);
339+
340+
// legacy queries (used by mongodb-driver:3.2.2)
341+
// i.e. with `$subType` instead of `$type`
342+
343+
// string queries (with respectively double and single quotes)
344+
testCall(
345+
db,
346+
String.format(
347+
"CALL apoc.mongo.count($uri, \"{'binary':{'$binary':'%s','$subType':'00'}}\")", bytesEncoded),
348+
params,
349+
consumer);
350+
351+
testCall(
352+
db,
353+
String.format(
354+
"CALL apoc.mongo.count($uri, '{\"binary\":{\"$binary\":\"%s\",\"$subType\":\"00\"}}')",
355+
bytesEncoded),
356+
params,
357+
consumer);
358+
359+
// map query
360+
testCall(
361+
db,
362+
String.format(
363+
"CALL apoc.mongo.count($uri, {binary: {`$binary`: '%s', `$subType`: '00'}})", bytesEncoded),
364+
params,
365+
consumer);
366+
}
367+
307368
@Test
308369
public void testWithSkip() {
309370
testResult(
@@ -478,7 +539,7 @@ public void testCountWithComplexTypes() {
478539
final String bytes = Base64.getEncoder().encodeToString("fooBar".getBytes());
479540
testCall(
480541
db,
481-
"CALL apoc.mongo.count($uri, {binary: {`$binary`: 'Zm9vQmFy', `$subType`: '00'}, int64: {`$numberLong`: '29'}})",
542+
"CALL apoc.mongo.count($uri, {binary: {`$binary`: 'Zm9vQmFy', `$type`: '00'}, int64: {`$numberLong`: '29'}})",
482543
map("uri", PERSON_URI, "bytes", bytes),
483544
r -> assertEquals(2L, r.get("value")));
484545
}
@@ -606,18 +667,19 @@ public void testInsertFailsWithDuplicateKey() {
606667
}
607668
}
608669

609-
@Ignore
610670
@Test
611671
public void shouldInsertDataIntoNeo4jWithFromDocument() throws Exception {
612672
Date date = DateUtils.parseDate("11-10-1935", "dd-MM-yyyy");
613673
testResult(
614674
db,
615-
"CALL apoc.mongo.find($uri, null, {extractReferences: true}) YIELD value "
675+
"CALL apoc.mongo.find($uri, {name: $name}, {extractReferences: true}) YIELD value "
616676
+ "CALL apoc.graph.fromDocument(value, $fromDocConfig) YIELD graph AS g1 "
617677
+ "RETURN g1",
618678
map(
619679
"uri",
620680
PERSON_URI,
681+
"name",
682+
"Andrea Santurbano",
621683
"fromDocConfig",
622684
map(
623685
"write",

0 commit comments

Comments
 (0)