Docs Menu
Docs Home
/
Atlas
/ /

How to Run Atlas Search Queries Across Multiple Collections

This page contains tutorials that demonstrate the different ways you can run Atlas Search queries across multiple collections:

  • To join collections and search across them, use $lookup with $search.

  • To combine search results from multiple collections, $unionWith with $search.

  • To consolidate multiple collections so you can index and search them together, use materialized views.

Before you begin, ensure that your Atlas cluster meets the requirements described in the Prerequisites.


➤ Use the Select your language drop-down menu on this page to set the language of the examples on this page.


Starting in v6.0, the MongoDB $lookup aggregation stage supports $search inside the $lookup pipeline option. Using $lookup, you can join multiple collections in the same database at query-time and run a $search query to further narrow down your search.

This tutorial demonstrates how to run a $lookup query with $search against the accounts and customers collections in the sample_analytics database. It takes you through the following steps:

  1. Create a default Atlas Search index on the accounts collection in the sample_analytics database.

  2. Run a $lookup query with $search to find customers from the customers collections whose accounts have purchased both CurrencyService and InvestmentStock products in the accounts collection.

To run $lookup query with $search, your cluster must run MongoDB v6.0 or later. To upgrade your MongoDB version, see Upgrade Major MongoDB Version for a Cluster.

$lookup queries are not very performant because Atlas Search does a full document lookup on the database for each document in the collection.

To learn more, see Reduce $lookup Operations.

Create an Atlas Search index named lookup-with-search-tutorial on all the fields in the sample_analytics.accounts collection.

1

Warning

Navigation Improvements In Progress

We're currently rolling out a new and improved navigation experience. If the following steps don't match your view in the Atlas UI, see the preview documentation.

  1. If it's not already displayed, select the organization that contains your desired project from the Organizations menu in the navigation bar.

  2. If it's not already displayed, select your desired project from the Projects menu in the navigation bar.

  3. If it's not already displayed, click Clusters in the sidebar.

    The Clusters page displays.

2

You can go the Atlas Search page from the sidebar, the Data Explorer, or your cluster details page.

  1. In the sidebar, click Atlas Search under the Services heading.

    If you have no clusters, click Create cluster to create one. To learn more, see Create a Cluster.

  2. If your project has multiple clusters, select the cluster you want to use from the Select cluster dropdown, then click Go to Atlas Search.

    The Atlas Search page displays.

  1. Click the Browse Collections button for your cluster.

  2. Expand the database and select the collection.

  3. Click the Search Indexes tab for the collection.

    The Atlas Search page displays.

  1. Click the cluster's name.

  2. Click the Atlas Search tab.

    The Atlas Search page displays.

3
4

Make the following selections on the page and then click Next.

Search Type

Select the Atlas Search index type.

Index Name and Data Source

Specify the following information:

  • Index Name: lookup-with-search-tutorial

  • Database and Collection:

    • sample_analytics database

    • accounts collection

Configuration Method

For a guided experience, select Visual Editor.

To edit the raw index definition, select JSON Editor.

Note

Your Atlas Search index is named default by default. If you keep this name, then your index will be the default Search index for any Atlas Search query that does not specify a different index option in its operators. If you are creating multiple indexes, we recommend that you maintain a consistent, descriptive naming convention across your indexes.

5

The following index definition dynamically indexes the fields of supported types in the collection. You can use the Atlas Search Visual Editor or the Atlas Search JSON Editor in the Atlas user interface to create the index.

Review the default index definition for the collection.

  1. Review the index definition.

    Your index definition should look similar to the following:

    {
    "mappings": {
    "dynamic": true
    }
    }
  2. Click Next.

6
7

A modal window displays to let you know your index is building. Click the Close button.

8

The index should take about one minute to build. While it is building, the Status column reads Build in Progress. When it is finished building, the Status column reads Active.


➤ Use the Select your language drop-down menu on this page to set the language of the examples in this section.


Connect to your Atlas cluster and run the sample query against the indexed collections in the sample_analytics database.

1

Open mongosh in a terminal window and connect to your cluster. For detailed instructions on connecting, see Connect via mongosh.

2

Run the following command at mongosh prompt:

use sample_analytics
switched to db sample_analytics
3

The following query uses the following stages:

  • $lookup to do the following:

    • Join customers and accounts collections in the sample_analytics database based on the account ID of the customers and return the matching documents from the accounts collection in an array field named purchases.

    • Use $search stage in the sub-pipeline to search for customer accounts that must have purchased both CurrencyService and InvestmentStock with preference for an order limit between 5000 to 10000.

  • $limit stage to limit the output to 5 results.

  • $project stage to exclude the specified fields in the results.

db.customers.aggregate([
{
$lookup:{
"from": "accounts",
"localField": "accounts",
"foreignField": "account_id",
"as": "purchases",
"pipeline": [{
"$search": {
"index": "lookup-with-search-tutorial",
"compound": {
"must": [{
"queryString": {
"defaultPath": "products",
"query": "products: (CurrencyService AND InvestmentStock)"
}
}],
"should": [{
"range": {
"path": "limit",
"gte": 5000,
"lte": 10000
}
}]
}
}
},{
"$project": {
"_id": 0
}
}]
}
},{
"$limit": 5
},{
"$project": {
"_id": 0,
"address": 0,
"birthdate": 0,
"username": 0,
"tier_and_details": 0
}
}
])
[
{
name: 'Elizabeth Ray',
email: 'arroyocolton@gmail.com',
active: true,
accounts: [ 371138, 324287, 276528, 332179, 422649, 387979 ],
purchases: [
{
account_id: 422649,
limit: 10000,
products: [ 'CurrencyService', 'InvestmentStock' ]
},
{
account_id: 324287,
limit: 10000,
products: [
'Commodity',
'CurrencyService',
'Derivatives',
'InvestmentStock'
]
},
{
account_id: 332179,
limit: 10000,
products: [
'Commodity',
'CurrencyService',
'InvestmentFund',
'Brokerage',
'InvestmentStock'
]
}
]
},
{
name: 'Lindsay Cowan',
email: 'cooperalexis@hotmail.com',
accounts: [ 116508 ],
purchases: []
},
{
name: 'Katherine David',
email: 'timothy78@hotmail.com',
accounts: [ 462501, 228290, 968786, 515844, 377292 ],
purchases: [
{
account_id: 228290,
limit: 10000,
products: [
'CurrencyService',
'InvestmentStock',
'InvestmentFund',
'Brokerage'
]
},
{
account_id: 515844,
limit: 10000,
products: [
'Commodity',
'CurrencyService',
'InvestmentFund',
'Brokerage',
'InvestmentStock'
]
}
]
},
{
name: 'Leslie Martinez',
email: 'tcrawford@gmail.com',
accounts: [ 170945, 951849 ],
purchases: []
},
{
name: 'Brad Cardenas',
email: 'dustin37@yahoo.com',
accounts: [ 721914, 817222, 973067, 260799, 87389 ],
purchases: [
{
account_id: 87389,
limit: 10000,
products: [ 'CurrencyService', 'InvestmentStock' ]
},
{
account_id: 260799,
limit: 10000,
products: [
'Brokerage',
'InvestmentStock',
'Commodity',
'CurrencyService'
]
}
]
}
]
1

Open MongoDB Compass and connect to your cluster. For detailed instructions on connecting, see Connect via Compass.

2

On the Database screen, click the sample_analytics database and then click the customers collection.

3

The following query uses the following stages:

  • $lookup to do the following:

    • Join customers and accounts collections in the sample_analytics database based on the account ID of the customers and return the matching documents from the accounts collection in an array field named purchases.

    • Use $search stage in the sub-pipeline to search for customer accounts that must have purchased both CurrencyService and InvestmentStock with preference for an order limit between 5000 to 10000.

  • $limit stage to limit the output to 5 results.

  • $project stage to exclude the specified fields in the results.

To run this query in MongoDB Compass:

  1. Click the Aggregations tab.

  2. Click Select..., then configure each of the following pipeline stages by selecting the stage from the dropdown and adding the query for that stage. Click Add Stage to add additional stages.

    Pipeline Stage
    Query

    $lookup

    {
    from: "accounts",
    localField: "accounts",
    foreignField: "account_id",
    as: "purchases",
    pipeline: [
    {
    $search: {
    index: "lookup-with-search-tutorial",
    compound: {
    must: [
    {
    queryString: {
    defaultPath: "products",
    query:
    "products: (CurrencyService AND InvestmentStock)"
    }
    }
    ],
    should: [
    {
    range: {
    path: "limit",
    gte: 5000,
    lte: 10000,
    }
    }
    ]
    }
    }
    },
    {
    $project: {
    _id: 0,
    }
    }
    ]
    }

    $limit

    5

    $project

    {
    _id: 0,
    address: 0,
    birthdate: 0,
    username: 0,
    tier_and_details: 0,
    }

    If you enabled Auto Preview, MongoDB Compass displays the following documents next to the $project pipeline stage:

    name: Elizabeth Ray
    email: arroyocolton@gmail.com
    active: True
    accounts: Array (6)
    purchases: Array (3)
    name: "Lindsay Cowan"
    email: "cooperalexis@hotmail.com"
    accounts: Array (1)
    purchases: Array (empty)
    name: "Katherine David"
    email: "timothy78@hotmail.com"
    accounts: Array (5)
    urchases: Array (2)
    name: "Leslie Martinez"
    email: "tcrawford@gmail.com"
    accounts: Array (2)
    purchases: Array (empty)
    name: "Brad Cardenas"
    email: "dustin37@yahoo.com"
    accounts: Array (5)
    purchases: Array (2)
4

MongoDB Compass might not display all the fields inside objects and all the values inside arrays for the documents it returns in the results. To view all the fields and values, expand the field in the results.

1
  1. Create a new directory called lookup-with-search and initialize your project with the dotnet new command.

    mkdir lookup-with-search
    cd lookup-with-search
    dotnet new console
  2. Add the .NET/C# Driver to your project as a dependency.

    dotnet add package MongoDB.Driver
2

The following query uses the following stages:

  • $lookup to do the following:

    • Join customers and accounts collections in the sample_analytics database based on the account ID of the customers and return the matching documents from the accounts collection in an array field named purchases.

    • Use $search stage in the sub-pipeline to search for customer accounts that must have purchased both CurrencyService and InvestmentStock with preference for an order limit between 5000 to 10000.

  • $limit stage to limit the output to 5 results.

  • $project stage to exclude the specified fields in the results.

1using MongoDB.Bson;
2using MongoDB.Bson.Serialization.Attributes;
3using MongoDB.Bson.Serialization.Conventions;
4using MongoDB.Driver;
5using MongoDB.Driver.Core;
6using MongoDB.Driver.Search;
7
8public class LookupWithSearch{
9
10 static void Main(string[] args) {// allow automapping of the camelCase database fields to our MovieDocument
11 var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() };
12 ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);
13
14 // connect to your Atlas cluster
15 var mongoClient = new MongoClient("<connection-string>");
16
17 // define namespace
18 var analyticsDatabase = mongoClient.GetDatabase("sample_analytics");
19 var accountsCollection = analyticsDatabase.GetCollection<AccountDocument>("accounts");
20 var customersCollection = analyticsDatabase.GetCollection<CustomerDocument>("customers");
21
22 // define pipeline stages
23 var lookupStage = new BsonDocument("$lookup", new BsonDocument{
24 { "from", "accounts" }, { "localField", "accounts" }, { "foreignField", "account_id" },
25 { "as", "purchases" }, { "pipeline", new BsonArray{
26 new BsonDocument("$search", new BsonDocument{
27 { "index", "lookup-with-search-tutorial" }, { "compound", new BsonDocument{
28 { "must", new BsonArray{
29 new BsonDocument("queryString", new BsonDocument{
30 { "defaultPath", "products" }, { "query", "products: (CurrencyService AND InvestmentStock)" }
31 })
32 }},
33 { "should", new BsonArray{
34 new BsonDocument("range", new BsonDocument{
35 { "path", "limit" }, { "gte", 5000 }, { "lte", 10000 }
36 })
37 }}
38 }}
39 })
40 }}
41 });
42 var projectStage1 = new BsonDocument("$project", new BsonDocument("_id", 0));
43 var limitStage = new BsonDocument("$limit", 5);
44 var projectStage2 = new BsonDocument("$project", new BsonDocument{
45 { "_id", 0 }, { "address", 0 }, { "birthdate", 0 }, { "username", 0 }, { "tier_and_details", 0 }
46 });
47 var aggregationPipeline = new List<BsonDocument> {lookupStage, projectStage1, limitStage, projectStage2};
48
49 // run pipeline
50 var results = customersCollection.Aggregate<BsonDocument>(aggregationPipeline).ToList();
51
52 // print results
53 foreach (var acct in results) {
54 Console.WriteLine(acct.ToJson());
55 }
56 }
57}
58
59// define fields in the accounts collection
60[BsonIgnoreExtraElements]
61public class AccountDocument {
62 [BsonId]
63 [BsonRepresentation(BsonType.ObjectId)]
64 [BsonElement("_id")]
65 public string Id { get; set; }
66
67 [BsonElement("account_id")]
68 public int AccountId { get; set; }
69
70 [BsonElement("limit")]
71 public int Limit { get; set; }
72}
73
74// define fields in the customers collection
75[BsonIgnoreExtraElements]
76public class CustomerDocument {
77 [BsonId]
78 [BsonRepresentation(BsonType.ObjectId)]
79 [BsonElement("_id")]
80 public ObjectId Id { get; set; }
81
82 [BsonElement("name")]
83 public string Name { get; set; }
84
85 [BsonElement("email")]
86 public string Email { get; set; }
87
88 [BsonElement("active")]
89 public bool Active { get; set; }
90
91 [BsonElement("accounts")]
92 public List<int> Accounts { get; set; }
93}
94
95// define new array field for matching documents
96public class CustomerLookedUp: CustomerDocument{
97 public List<CustomerDocument> Purchases { get; set; }
98}
3

Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.

4
dotnet run lookup-with-search.csproj
{
"name" : "Elizabeth Ray",
"email" : "arroyocolton@gmail.com",
"active" : true,
"accounts" : [371138, 324287, 276528, 332179, 422649,
387979],
"purchases" : [
{
"_id" : ObjectId("5ca4bbc7a2dd94ee58162402"),
"account_id" : 422649,
"limit" : 10000,
"products" : ["CurrencyService", "InvestmentStock"]
},
{
"_id" : ObjectId("5ca4bbc7a2dd94ee581623a9"),
"account_id" : 324287,
"limit" : 10000,
"products" : ["Commodity", "CurrencyService", "Derivatives", "InvestmentStock"]
},
{
"_id" : ObjectId("5ca4bbc7a2dd94ee58162400"),
"account_id" : 332179,
"limit" : 10000,
"products" : ["Commodity", "CurrencyService", "InvestmentFund", "Brokerage", "InvestmentStock"]
}
]
}
{
"name" : "Lindsay Cowan",
"email" : "cooperalexis@hotmail.com",
"accounts" : [116508],
"purchases" : []
}
{
"name" : "Katherine David",
"email" : "timothy78@hotmail.com",
"accounts" : [462501, 228290, 968786, 515844, 377292],
"purchases" : [
{
"_id" : ObjectId("5ca4bbc7a2dd94ee581623c9"),
"account_id" : 228290,
"limit" : 10000,
"products" : ["CurrencyService", "InvestmentStock", "InvestmentFund", "Brokerage"] },
{
"_id" : ObjectId("5ca4bbc7a2dd94ee581623cb"),
"account_id" : 515844,
"limit" : 10000,
"products" : ["Commodity", "CurrencyService", "InvestmentFund", "Brokerage", "InvestmentStock"]
}
]
}
{
"name" : "Leslie Martinez",
"email" : "tcrawford@gmail.com",
"accounts" : [170945, 951849],
"purchases" : []
}
{
"name" : "Brad Cardenas",
"email" : "dustin37@yahoo.com",
"accounts" : [721914, 817222, 973067, 260799, 87389],
"purchases" : [
{
"_id" : ObjectId("5ca4bbc7a2dd94ee581623d6"),
"account_id" : 87389,
"limit" : 10000,
"products" : ["CurrencyService", "InvestmentStock"] },
{
"_id" : ObjectId("5ca4bbc7a2dd94ee581623d5"),
"account_id" : 260799,
"limit" : 10000,
"products" : ["Brokerage", "InvestmentStock", "Commodity", "CurrencyService"]
}
]
}
1
2

The following query uses the following stages:

  • $lookup to do the following:

    • Join customers and accounts collections in the sample_analytics database based on the account ID of the customers and return the matching documents from the accounts collection in an array field named purchases.

    • Use $search stage in the sub-pipeline to search for customer accounts that must have purchased both CurrencyService and InvestmentStock with preference for an order limit between 5000 to 10000.

  • $limit stage to limit the output to 5 results.

  • $project stage to exclude the specified fields in the results.

1package main
2
3import (
4 "context"
5 "fmt"
6 "time"
7
8 "go.mongodb.org/mongo-driver/v2/bson"
9 "go.mongodb.org/mongo-driver/v2/mongo"
10 "go.mongodb.org/mongo-driver/v2/mongo/options"
11)
12
13func main() {
14 var err error
15 // connect to the Atlas cluster
16 ctx := context.Background()
17 clOpts := options.Client().ApplyURI("<connection-string>").SetTimeout(5 * time.Second)
18 client, err := mongo.Connect(clOpts)
19 if err != nil {
20 panic(err)
21 }
22 defer client.Disconnect(ctx)
23 // set namespace
24 collection := client.Database("sample_analytics").Collection("customers")
25 // define pipeline
26 lookupStage := bson.D{{Key: "$lookup", Value: bson.D{
27 {Key: "from", Value: "accounts"},
28 {Key: "localField", Value: "accounts"},
29 {Key: "foreignField", Value: "account_id"},
30 {Key: "as", Value: "purchases"},
31 {Key: "pipeline", Value: bson.A{
32 bson.D{
33 {Key: "$search", Value: bson.D{
34 {Key: "index", Value: "lookup-with-search-tutorial"},
35 {Key: "compound", Value: bson.D{
36 {Key: "must", Value: bson.A{
37 bson.D{{Key: "queryString", Value: bson.D{
38 {Key: "defaultPath", Value: "products"},
39 {Key: "query", Value: "products: (CurrencyService AND InvestmentStock)"},
40 }}},
41 }},
42 {Key: "should", Value: bson.A{
43 bson.D{{Key: "range", Value: bson.D{
44 {Key: "path", Value: "limit"},
45 {Key: "gte", Value: 5000},
46 {Key: "lte", Value: 10000},
47 }}},
48 }},
49 }},
50 }},
51 },
52 bson.D{{Key: "$project", Value: bson.D{
53 {Key: "_id", Value: 0},
54 {Key: "address", Value: 0},
55 {Key: "birthdate", Value: 0},
56 {Key: "username", Value: 0},
57 {Key: "tier_and_details", Value: 0},
58 }}},
59 }},
60 }}}
61 limitStage := bson.D{{Key: "$limit", Value: 5}}
62 projectStage := bson.D{{Key: "$project", Value: bson.D{
63 {Key: "name", Value: 1},
64 {Key: "email", Value: 1},
65 {Key: "active", Value: 1},
66 {Key: "accounts", Value: 1},
67 {Key: "purchases", Value: 1},
68 }}}
69
70 // run pipeline
71 cursor, err := collection.Aggregate(ctx, mongo.Pipeline{lookupStage, limitStage, projectStage})
72 if err != nil {
73 panic(err)
74 }
75 // print results
76 var results []bson.D
77 if err = cursor.All(context.TODO(), &results); err != nil {
78 panic(err)
79 }
80 for _, result := range results {
81 fmt.Println(result)
82 }
83}
3

Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.

4
go run lookup-with-search-query.go
{"_id":...,"name":"Gary Nichols","email":"laura34@yahoo.com","accounts":[{"$numberInt":"385397"},{"$numberInt":"337979"},{"$numberInt":"325377"},{"$numberInt":"440243"},{"$numberInt":"586395"},{"$numberInt":"86702"}],"purchases":[{"account_id":{"$numberInt":"337979"},"limit":{"$numberInt":"10000"},"products":["Brokerage","Derivatives","InvestmentStock","CurrencyService"]}]}
{"_id":...,"name":"Ashley Lopez","email":"michael16@hotmail.com","accounts":[{"$numberInt":"662207"},{"$numberInt":"816481"}],"purchases":[]}
{"_id":...,"name":"John Parks","email":"zmelton@gmail.com","accounts":[{"$numberInt":"702610"},{"$numberInt":"240640"}],"purchases":[{"account_id":{"$numberInt":"702610"},"limit":{"$numberInt":"10000"},"products":["Commodity","CurrencyService","InvestmentStock"]}]}
{"_id":...,"name":"Jennifer Lawrence","email":"scott50@yahoo.com","accounts":[{"$numberInt":"344885"},{"$numberInt":"839927"},{"$numberInt":"853542"}],"purchases":[{"account_id":{"$numberInt":"853542"},"limit":{"$numberInt":"10000"},"products":["CurrencyService","InvestmentStock"]},{"account_id":{"$numberInt":"344885"},"limit":{"$numberInt":"10000"},"products":["Commodity","InvestmentFund","CurrencyService","InvestmentStock"]},{"account_id":{"$numberInt":"839927"},"limit":{"$numberInt":"10000"},"products":["InvestmentFund","CurrencyService","Brokerage","Commodity","InvestmentStock"]}]}
{"_id":...,"name":"Jacqueline Haynes","email":"virginia36@hotmail.com","accounts":[{"$numberInt":"631901"},{"$numberInt":"814687"}],"purchases":[]}
1

junit

4.11 or higher version

mongodb-driver-sync

4.3.0 or higher version

slf4j-log4j12

1.7.30 or higher version

2
3

The following query uses the following stages:

  • $lookup to do the following:

    • Join customers and accounts collections in the sample_analytics database based on the account ID of the customers and return the matching documents from the accounts collection in an array field named purchases.

    • Use $search stage in the sub-pipeline to search for customer accounts that must have purchased both CurrencyService and InvestmentStock with preference for an order limit between 5000 to 10000.

  • $limit stage to limit the output to 5 results.

  • $project stage to exclude the specified fields in the results.

1import static com.mongodb.client.model.Aggregates.limit;
2import static com.mongodb.client.model.Aggregates.project;
3import static com.mongodb.client.model.Projections.*;
4import java.util.Arrays;
5import com.mongodb.client.MongoClient;
6import com.mongodb.client.MongoClients;
7import com.mongodb.client.MongoCollection;
8import com.mongodb.client.MongoDatabase;
9import org.bson.Document;
10
11public class LookupWithSearchQuery {
12
13 public static void main(String[] args) {
14 // connect to your Atlas cluster
15 String uri = "<connection-string>";
16
17 try (MongoClient mongoClient = MongoClients.create(uri)) {
18 // set namespace
19 MongoDatabase database = mongoClient.getDatabase("sample_analytics");
20 MongoCollection<Document> collection = database.getCollection("customers");
21
22 // define pipeline
23 Document agg = new Document("$lookup",
24 new Document("from", "accounts")
25 .append("localField", "accounts")
26 .append("foreignField", "account_id")
27 .append("as", "purchases")
28 .append("pipeline", Arrays.asList(new Document("$search",
29 new Document("index", "lookup-with-search-tutorial")
30 .append("compound",
31 new Document("must", Arrays.asList(new Document("queryString",
32 new Document("defaultPath", "products")
33 .append("query", "products: (CurrencyService AND InvestmentStock)"))))
34 .append("should", Arrays.asList(new Document("range",
35 new Document("path", "limit")
36 .append("gte", 5000L)
37 .append("lte", 10000L)
38 )))
39 )
40 ),
41 new Document("$limit", 5L),
42 new Document("$project",
43 new Document("_id", 0L)
44 .append("address", 0L)
45 .append("birthdate", 0L)
46 .append("username", 0L)
47 .append("tier_and_details", 0L)
48 )))
49 );
50 // run pipeline and print results
51 collection.aggregate(Arrays.asList(agg,
52 limit(5),
53 project(fields(excludeId(), include("name", "email", "active", "accounts", "purchases")))
54 ))
55 .forEach(doc -> System.out.println(doc.toJson()));
56 }
57 }
58}

Note

To run the sample code in your Maven environment, add the following code above the import statements in your file.

package com.mongodb.drivers;
4

Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.

5
javac LookupWithSearchQuery.java
java LookupWithSearchQuery
{"name": "Elizabeth Ray", "email": "arroyocolton@gmail.com", "active": true, "accounts": [371138, 324287, 276528, 332179, 422649, 387979], "purchases": [{"account_id": 422649, "limit": 10000, "products": ["CurrencyService", "InvestmentStock"]}, {"account_id": 324287, "limit": 10000, "products": ["Commodity", "CurrencyService", "Derivatives", "InvestmentStock"]}, {"account_id": 332179, "limit": 10000, "products": ["Commodity", "CurrencyService", "InvestmentFund", "Brokerage", "InvestmentStock"]}]}
{"name": "Lindsay Cowan", "email": "cooperalexis@hotmail.com", "accounts": [116508], "purchases": []}
{"name": "Katherine David", "email": "timothy78@hotmail.com", "accounts": [462501, 228290, 968786, 515844, 377292], "purchases": [{"account_id": 228290, "limit": 10000, "products": ["CurrencyService", "InvestmentStock", "InvestmentFund", "Brokerage"]}, {"account_id": 515844, "limit": 10000, "products": ["Commodity", "CurrencyService", "InvestmentFund", "Brokerage", "InvestmentStock"]}]}
{"name": "Leslie Martinez", "email": "tcrawford@gmail.com", "accounts": [170945, 951849], "purchases": []}
{"name": "Brad Cardenas", "email": "dustin37@yahoo.com", "accounts": [721914, 817222, 973067, 260799, 87389], "purchases": [{"account_id": 87389, "limit": 10000, "products": ["CurrencyService", "InvestmentStock"]}, {"account_id": 260799, "limit": 10000, "products": ["Brokerage", "InvestmentStock", "Commodity", "CurrencyService"]}]}
1

mongodb-driver-kotlin-coroutine

4.10.0 or higher version

2
3

The following query uses the following stages:

  • $lookup to do the following:

    • Join customers and accounts collections in the sample_analytics database based on the account ID of the customers and return the matching documents from the accounts collection in an array field named purchases.

    • Use $search stage in the sub-pipeline to search for customer accounts that must have purchased both CurrencyService and InvestmentStock with preference for an order limit between 5000 to 10000.

  • $limit stage to limit the output to 5 results.

  • $project stage to exclude the specified fields in the results.

1import com.mongodb.client.model.Aggregates.limit
2import com.mongodb.client.model.Aggregates.project
3import com.mongodb.client.model.Projections.*
4import com.mongodb.kotlin.client.coroutine.MongoClient
5import kotlinx.coroutines.runBlocking
6import org.bson.Document
7import java.util.*
8
9fun main() {
10 // connect to your Atlas cluster
11 val uri = "<connection-string>"
12 val mongoClient = MongoClient.create(uri)
13
14 // set namespace
15 val database = mongoClient.getDatabase("sample_analytics")
16 val collection = database.getCollection<Document>("customers")
17
18 runBlocking {
19 // define pipeline
20 val agg = Document(
21 "\$lookup",
22 Document("from", "accounts")
23 .append("localField", "accounts")
24 .append("foreignField", "account_id")
25 .append("as", "purchases")
26 .append(
27 "pipeline", Arrays.asList(
28 Document(
29 "\$search",
30 Document("index", "lookup-with-search-tutorial")
31 .append(
32 "compound",
33 Document(
34 "must", Arrays.asList(
35 Document(
36 "queryString",
37 Document("defaultPath", "products")
38 .append("query", "products: (CurrencyService AND InvestmentStock)")
39 )
40 )
41 )
42 .append(
43 "should", Arrays.asList(
44 Document(
45 "range",
46 Document("path", "limit")
47 .append("gte", 5000)
48 .append("lte", 10000)
49 )
50 )
51 )
52 )
53 ),
54 Document("\$limit", 5),
55 Document(
56 "\$project",
57 Document("_id", 0)
58 .append("address", 0)
59 .append("birthdate", 0)
60 .append("username", 0)
61 .append("tier_and_details", 0)
62 )
63 )
64 )
65 )
66
67 // run pipeline and print results
68 val resultsFlow = collection.aggregate<Document>(
69 listOf(
70 agg,
71 limit(5),
72 project(fields(excludeId(), include("name", "email", "active", "accounts", "purchases")))
73 )
74 )
75 resultsFlow.collect { println(it) }
76 }
77 mongoClient.close()
78}
4

Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.

5

When you run the LookupWithSearchQuery.kt program in your IDE, it prints the following documents:

Document{{name=Elizabeth Ray, email=arroyocolton@gmail.com, active=true, accounts=[371138, 324287, 276528, 332179, 422649, 387979], purchases=[Document{{account_id=422649, limit=10000, products=[CurrencyService, InvestmentStock]}}, Document{{account_id=324287, limit=10000, products=[Commodity, CurrencyService, Derivatives, InvestmentStock]}}, Document{{account_id=332179, limit=10000, products=[Commodity, CurrencyService, InvestmentFund, Brokerage, InvestmentStock]}}]}}
Document{{name=Lindsay Cowan, email=cooperalexis@hotmail.com, accounts=[116508], purchases=[]}}
Document{{name=Katherine David, email=timothy78@hotmail.com, accounts=[462501, 228290, 968786, 515844, 377292], purchases=[Document{{account_id=228290, limit=10000, products=[CurrencyService, InvestmentStock, InvestmentFund, Brokerage]}}, Document{{account_id=515844, limit=10000, products=[Commodity, CurrencyService, InvestmentFund, Brokerage, InvestmentStock]}}]}}
Document{{name=Leslie Martinez, email=tcrawford@gmail.com, accounts=[170945, 951849], purchases=[]}}
Document{{name=Brad Cardenas, email=dustin37@yahoo.com, accounts=[721914, 817222, 973067, 260799, 87389], purchases=[Document{{account_id=87389, limit=10000, products=[CurrencyService, InvestmentStock]}}, Document{{account_id=260799, limit=10000, products=[Brokerage, InvestmentStock, Commodity, CurrencyService]}}]}}
1
2

The following query uses the following stages:

  • $lookup to do the following:

    • Join customers and accounts collections in the sample_analytics database based on the account ID of the customers and return the matching documents from the accounts collection in an array field named purchases.

    • Use $search stage in the sub-pipeline to search for customer accounts that must have purchased both CurrencyService and InvestmentStock with preference for an order limit between 5000 to 10000.

  • $limit stage to limit the output to 5 results.

  • $project stage to exclude the specified fields in the results.

1const MongoClient = require("mongodb").MongoClient;
2const assert = require("assert");
3
4const agg = [
5 {
6 '$lookup': {
7 'from': 'accounts',
8 'localField': 'accounts',
9 'foreignField': 'account_id',
10 'as': 'purchases',
11 'pipeline': [
12 {
13 '$search': {
14 'index': 'lookup-with-search-tutorial',
15 'compound': {
16 'must': [
17 {
18 'queryString': {
19 'defaultPath': 'products',
20 'query': 'products: (CurrencyService AND InvestmentStock)'
21 }
22 }
23 ],
24 'should': [
25 {
26 'range': {
27 'path': 'limit',
28 'gte': 5000,
29 'lte': 10000
30 }
31 }
32 ]
33 }
34 }
35 }, {
36 '$project': {
37 '_id': 0
38 }
39 }
40 ]
41 }
42 }, {
43 '$limit': 5
44 }, {
45 '$project': {
46 '_id': 0,
47 'address': 0,
48 'birthdate': 0,
49 'username': 0,
50 'tier_and_details': 0
51 }
52 }
53 ];
54
55MongoClient.connect(
56 "<connection-string>",
57 { useNewUrlParser: true, useUnifiedTopology: true },
58 async function (connectErr, client) {
59 assert.equal(null, connectErr);
60 const coll = client.db("sample_analytics").collection("customers");
61 let cursor = await coll.aggregate(agg);
62 await cursor.forEach((doc) => console.log(doc));
63 client.close();
64 }
65);
3

Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.

4

Run the following command to query your collection:

node lookup-with-search-query.js
{
name: 'Elizabeth Ray',
email: 'arroyocolton@gmail.com',
active: true,
accounts: [ 371138, 324287, 276528, 332179, 422649, 387979 ],
purchases: [
{ account_id: 422649, limit: 10000, products: [Array] },
{ account_id: 324287, limit: 10000, products: [Array] },
{ account_id: 332179, limit: 10000, products: [Array] }
]
}
{
name: 'Lindsay Cowan',
email: 'cooperalexis@hotmail.com',
accounts: [ 116508 ],
purchases: []
}
{
name: 'Katherine David',
email: 'timothy78@hotmail.com',
accounts: [ 462501, 228290, 968786, 515844, 377292 ],
purchases: [
{ account_id: 228290, limit: 10000, products: [Array] },
{ account_id: 515844, limit: 10000, products: [Array] }
]
}
{
name: 'Leslie Martinez',
email: 'tcrawford@gmail.com',
accounts: [ 170945, 951849 ],
purchases: []
}
{
name: 'Brad Cardenas',
email: 'dustin37@yahoo.com',
accounts: [ 721914, 817222, 973067, 260799, 87389 ],
purchases: [
{ account_id: 87389, limit: 10000, products: [Array] },
{ account_id: 260799, limit: 10000, products: [Array] }
]
}
1
2

The following query uses the following stages:

  • $lookup to do the following:

    • Join customers and accounts collections in the sample_analytics database based on the account ID of the customers and return the matching documents from the accounts collection in an array field named purchases.

    • Use $search stage in the sub-pipeline to search for customer accounts that must have purchased both CurrencyService and InvestmentStock with preference for an order limit between 5000 to 10000.

  • $limit stage to limit the output to 5 results.

  • $project stage to exclude the specified fields in the results.

1import pymongo
2
3# connect to your Atlas cluster
4client = pymongo.MongoClient('<connection-string>')
5
6# define pipeline
7pipeline = [
8 {
9 '$lookup': {
10 'from': 'accounts',
11 'localField': 'accounts',
12 'foreignField': 'account_id',
13 'as': 'purchases',
14 'pipeline': [
15 {
16 '$search': {
17 'index': 'lookup-with-search-tutorial',
18 'compound': {
19 'must': [
20 {
21 'queryString': {
22 'defaultPath': 'products',
23 'query': 'products: (CurrencyService AND InvestmentStock)'
24 }
25 }
26 ],
27 'should': [
28 {
29 'range': {
30 'path': 'limit',
31 'gte': 5000,
32 'lte': 10000
33 }
34 }
35 ]
36 }
37 }
38 },
39 { '$project': { '_id': 0 } }
40 ]
41 }
42 },
43 { '$limit': 5 },
44 {
45 '$project': {
46 '_id': 0,
47 'address': 0,
48 'birthdate': 0,
49 'username': 0,
50 'tier_and_details': 0
51 }
52 }
53]
54
55# run pipeline
56result = client['sample_analytics']['customers'].aggregate(pipeline)
57
58# print results
59for i in result:
60 print(i)
3

Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.

4
python lookup-with-search-query.py
{'name': 'Elizabeth Ray', 'email': 'arroyocolton@gmail.com', 'active': True, 'accounts': [371138, 324287, 276528, 332179, 422649, 387979], 'purchases': [{'account_id': 422649, 'limit': 10000, 'products': ['CurrencyService', 'InvestmentStock']}, {'account_id': 324287, 'limit': 10000, 'products': ['Commodity', 'CurrencyService', 'Derivatives', 'InvestmentStock']}, {'account_id': 332179, 'limit': 10000, 'products': ['Commodity', 'CurrencyService', 'InvestmentFund', 'Brokerage', 'InvestmentStock']}]}
{'name': 'Lindsay Cowan', 'email': 'cooperalexis@hotmail.com', 'accounts': [116508], 'purchases': []}
{'name': 'Katherine David', 'email': 'timothy78@hotmail.com', 'accounts': [462501, 228290, 968786, 515844, 377292], 'purchases': [{'account_id': 228290, 'limit': 10000, 'products': ['CurrencyService', 'InvestmentStock', 'InvestmentFund', 'Brokerage']}, {'account_id': 515844, 'limit': 10000, 'products': ['Commodity', 'CurrencyService', 'InvestmentFund', 'Brokerage', 'InvestmentStock']}]}
{'name': 'Leslie Martinez', 'email': 'tcrawford@gmail.com', 'accounts': [170945, 951849], 'purchases': []}
{'name': 'Brad Cardenas', 'email': 'dustin37@yahoo.com', 'accounts': [721914, 817222, 973067, 260799, 87389], 'purchases': [{'account_id': 87389, 'limit': 10000, 'products': ['CurrencyService', 'InvestmentStock']}, {'account_id': 260799, 'limit': 10000, 'products': ['Brokerage', 'InvestmentStock', 'Commodity', 'CurrencyService']}]}

Starting in v6.0, the MongoDB $unionWith aggregation stage supports $search inside the $unionWith pipeline option. Using $unionWith, you can combine $search results from multiple collections in the same database in the result set.

This tutorial demonstrates how to run a $unionWith query with $search against the companies and inspections collections in the sample_training database. It takes you through the following steps:

  1. Create a default Atlas Search index on the companies and inspections collections in the sample_training database.

  2. Run a $unionWith query with $search to perform a union of companies with mobile in their name from both the companies and inspections collections.

Note

To run a $unionWith query with $search, your cluster must run MongoDB v6.0 or higher. To upgrade your MongoDB version, see Upgrade Major MongoDB Version for a Cluster.

In this section, you will create an Atlas Search index named default on all the fields in the companies collection in the sample_training database. You will create another Atlas Search index named default on all the fields in the inspections collection in the sample_training database. You must perform the following steps for each collection.

1

Warning

Navigation Improvements In Progress

We're currently rolling out a new and improved navigation experience. If the following steps don't match your view in the Atlas UI, see the preview documentation.

  1. If it's not already displayed, select the organization that contains your desired project from the Organizations menu in the navigation bar.

  2. If it's not already displayed, select your desired project from the Projects menu in the navigation bar.

  3. If it's not already displayed, click Clusters in the sidebar.

    The Clusters page displays.

2

You can go the Atlas Search page from the sidebar, the Data Explorer, or your cluster details page.

  1. In the sidebar, click Atlas Search under the Services heading.

    If you have no clusters, click Create cluster to create one. To learn more, see Create a Cluster.

  2. If your project has multiple clusters, select the cluster you want to use from the Select cluster dropdown, then click Go to Atlas Search.

    The Atlas Search page displays.

  1. Click the Browse Collections button for your cluster.

  2. Expand the database and select the collection.

  3. Click the Search Indexes tab for the collection.

    The Atlas Search page displays.

  1. Click the cluster's name.

  2. Click the Atlas Search tab.

    The Atlas Search page displays.

3
4

Make the following selections on the page and then click Next.

Search Type

Select the Atlas Search index type.

Index Name and Data Source

Specify the following information:

  • Index Name: default

  • Database and Collection:

    • sample_training database

    • companies or inspections collection

Configuration Method

For a guided experience, select Visual Editor.

To edit the raw index definition, select JSON Editor.

Note

Your Atlas Search index is named default by default. If you keep this name, then your index will be the default Search index for any Atlas Search query that does not specify a different index option in its operators. If you are creating multiple indexes, we recommend that you maintain a consistent, descriptive naming convention across your indexes.

5

The following index definition dynamically indexes the fields of supported types in the collection. You can use the Atlas Search Visual Editor or the Atlas Search JSON Editor in the Atlas user interface to create the index.

Review the "default" index definition for the collection.

  1. Review the index definition.

    Your index definition should look similar to the following example:

    {
    "mappings": {
    "dynamic": true
    }
    }
6
7

A modal window displays to let you know your index is building. Click the Close button.

8

The index should take about one minute to build. While it is building, the Status column reads Build in Progress. When it is finished building, the Status column reads Active.

In this section, you will connect to your Atlas cluster and run the sample query against the indexed collections in the sample_training database.

1

Open mongosh in a terminal window and connect to your cluster. For detailed instructions on connecting, see Connect via mongosh.

2

Run the following command at mongosh prompt:

use sample_training
switched to db sample_training
3

The following query searches both the companies and inspections collections for the term mobile in the name and business_name fields respectively.

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $set stage to add a new field named source that identifies the collection of the output documents.

    • $limit stage to limit the output to 3 results from each collection.

    • $project stage to:

      • Include only the specified fields in the results.

      • Add a field named score.

db.companies.aggregate([
{
"$search": {
"text": {
"query": "Mobile",
"path": "name"
}
}
}, {
"$project": {
"score": {
"$meta": "searchScore"
},
"_id": 0,
"number_of_employees": 1,
"founded_year": 1,
"name": 1
}
}, {
"$set": {
"source": "companies"
}
}, {
"$limit": 3
}, {
"$unionWith": {
"coll": "inspections",
"pipeline": [
{
"$search": {
"text": {
"query": "Mobile",
"path": "business_name"
}
}
}, {
"$set": {
"source": "inspections"
}
}, {
"$project": {
"score": {
"$meta": "searchScore"
},
"source": 1,
"_id": 0,
"business_name": 1,
"address": 1
}
}, {
"$limit": 3
}, {
"$sort": {
"score": -1
}
}
]
}
}
])
[
{
name: 'XLR8 Mobile',
number_of_employees: 21,
founded_year: 2006,
score: 2.0815043449401855,
source: 'companies'
},
{
name: 'Pulse Mobile',
number_of_employees: null,
founded_year: null,
score: 2.0815043449401855,
source: 'companies'
},
{
name: 'T-Mobile',
number_of_employees: null,
founded_year: null,
score: 2.0815043449401855,
source: 'companies'
},
{
business_name: 'T. MOBILE',
address: { city: 'BROOKLYN', zip: 11209, street: '86TH ST', number: 440 },
score: 2.900916337966919,
source: 'inspections'
},
{
business_name: 'BOOST MOBILE',
address: { city: 'BRONX', zip: 10458, street: 'E FORDHAM RD', number: 261 },
score: 2.900916337966919,
source: 'inspections'
},
{
business_name: 'SPRING MOBILE',
address: {
city: 'SOUTH RICHMOND HILL',
zip: 11419,
street: 'LIBERTY AVE',
number: 12207
},
score: 2.900916337966919,
source: 'inspections'
}
]

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $addFields stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A field name source_count that shows a count of the output documents.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $limit stage to limit the output to 3 results from each collection.

  • $set stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A new field named source_count that shows a count of the output documents.

db.companies.aggregate([
{
"$search": {
"text": {
"query": "mobile",
"path": "name",
"score": {
"boost": {
"value": 1.6
}
}
}
}
}, {
"$project": {
"score": {
"$meta": "searchScore"
},
"_id": 0,
"number_of_employees": 1,
"founded_year": 1,
"name": 1
}
}, {
"$addFields": {
"source": "companies",
"source_count": "$$SEARCH_META.count.lowerBound"
}
}, {
"$limit": 3
}, {
"$unionWith": {
"coll": "inspections",
"pipeline": [
{
"$search": {
"text": {
"query": "mobile",
"path": "business_name"
}
}
}, {
"$project": {
"score": {
"$meta": "searchScore"
},
"business_name": 1,
"address": 1,
"_id": 0
}
}, {
"$limit": 3
}, {
"$set": {
"source": "inspections",
"source_count": "$$SEARCH_META.count.lowerBound"
}
}, {
"$sort": {
"score": -1
}
}
]
}
}, {
"$facet": {
"allDocs": [],
"totalCount": [
{
"$group": {
"_id": "$source",
"firstCount": {
"$first": "$source_count"
}
}
}, {
"$project": {
"totalCount": {
"$sum": "$firstCount"
}
}
}
]
}
}
])
[
{
allDocs: [
{
name: 'XLR8 Mobile',
number_of_employees: 21,
founded_year: 2006,
score: 3.33040714263916,
source: 'companies',
source_count: Long("52")
},
{
name: 'Pulse Mobile',
number_of_employees: null,
founded_year: null,
score: 3.33040714263916,
source: 'companies',
source_count: Long("52")
},
{
name: 'T-Mobile',
number_of_employees: null,
founded_year: null,
score: 3.33040714263916,
source: 'companies',
source_count: Long("52")
},
{
business_name: 'T. MOBILE',
address: {
city: 'BROOKLYN',
zip: 11209,
street: '86TH ST',
number: 440
},
score: 2.900916337966919,
source: 'inspections',
source_count: Long("456")
},
{
business_name: 'BOOST MOBILE',
address: {
city: 'BRONX',
zip: 10458,
street: 'E FORDHAM RD',
number: 261
},
score: 2.900916337966919,
source: 'inspections',
source_count: Long("456")
},
{
business_name: 'SPRING MOBILE',
address: {
city: 'SOUTH RICHMOND HILL',
zip: 11419,
street: 'LIBERTY AVE',
number: 12207
},
score: 2.900916337966919,
source: 'inspections',
source_count: Long("456")
}
],
totalCount: [
{ _id: 'companies', totalCount: Long("52") },
{ _id: 'inspections', totalCount: Long("456") }
]
}
]
1

Open MongoDB Compass and connect to your cluster. For detailed instructions on connecting, see Connect via Compass.

2

On the Database screen, click the sample_training database and then click the companies collection.

3

The following query searches both the companies and inspections collections for the term mobile in the name and business_name fields respectively.

To run this query in MongoDB Compass:

  1. Click the Aggregations tab.

  2. Click Select..., then configure each of the following pipeline stages by selecting the stage from the dropdown and adding the query for that stage. Click Add Stage to add additional stages.

    This query uses the following stages:

    • $search to search for companies that include mobile in the name.

    • $unionWith to do the following:

      • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

      • Perform a union of documents from the companies and documents from the inspections collections.

    • $set stage to add a new field named source that identifies the collection of the output documents.

      • $limit stage to limit the output to 3 results from each collection.

      • $project stage to:

        • Include only the specified fields in the results.

        • Add a field named score.

    Pipeline Stage
    Query

    $search

    {
    "text": {
    "query": "Mobile",
    "path": "name"
    }
    }

    $project

    {
    "score": {
    "$meta": "searchScore",
    },
    "_id": 0,
    "number_of_employees": 1,
    "founded_year": 1,
    "name": 1
    }

    $set

    {
    "source": "companies"
    }

    $limit

    3

    $unionWith

    {
    "coll": "inspections",
    "pipeline": [
    {
    "$search": {
    "text": {
    "query": "Mobile",
    "path": "business_name",
    }
    }
    },
    {
    "$set": {
    "source": "inspections",
    }
    },
    {
    "$project": {
    "score": {
    "$meta": "searchScore"
    },
    "source": 1,
    "_id": 0,
    "business_name": 1,
    "address": 1
    }
    },
    {
    "$limit": 3
    },
    {
    "$sort": {
    "score": -1
    }
    }
    ]
    }

    If you enabled Auto Preview, MongoDB Compass displays the following documents next to the $project pipeline stage:

    name: "XLR8 Mobile"
    number_of_employees: 21
    founded_year: 2006
    score: 2.0815043449401855
    source: "companies"
    name: "Pulse Mobile"
    number_of_employees: null
    founded_year: null
    score: 2.0815043449401855
    source: "companies"
    name: "T-Mobile"
    number_of_employees: null
    founded_year: null
    score: 2.0815043449401855
    source: "companies"
    business_name: "T. MOBILE"
    address: Object
    source: "inspections"
    score: 2.900916337966919
    business_name: "BOOST MOBILE"
    address: Object
    source: "inspections"
    score: 2.900916337966919
    business_name: "SPRING MOBILE"
    address: Object
    source: "inspections"
    score: 2.900916337966919

    This query uses the following stages:

    • $search to search for companies that include mobile in the name.

    • $project stage to:

      • Include only the specified fields in the results.

      • Add a field named score.

    • $addFields stage to add the following new fields:

      • A new field named source that identifies the collection of the output documents.

      • A field name source_count that shows a count of the output documents.

    • $unionWith to do the following:

      • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

      • Perform a union of documents from the companies and documents from the inspections collections.

    • $project stage to:

      • Include only the specified fields in the results.

      • Add a field named score.

    • $limit stage to limit the output to 3 results from each collection.

    • $set stage to add the following new fields:

      • A new field named source that identifies the collection of the output documents.

      • A new field named source_count that shows a count of the output documents.

    Pipeline Stage
    Query

    $search

    {
    text: {
    query: "mobile",
    path: "name",
    score: {
    boost: {
    value: 1.6
    }
    }
    }
    }

    $project

    {
    "score": {
    "$meta": "searchScore",
    },
    "_id": 0,
    "number_of_employees": 1,
    "founded_year": 1,
    "name": 1
    }

    $addFields

    {
    source: "companies",
    source_count: "$$SEARCH_META.count.lowerBound"
    }

    $limit

    3

    $unionWith

    {
    coll: "inspections",
    pipeline: [
    {
    $search: {
    text: {
    query: "mobile",
    path: "business_name"
    }
    }
    },
    {
    $project: {
    score: {
    $meta: "searchScore"
    },
    business_name: 1,
    address: 1,
    _id: 0
    }
    },
    {
    $limit: 3,
    },
    {
    $set: {
    source: "inspections",
    source_count: "$$SEARCH_META.count.lowerBound"
    }
    },
    {
    $sort: {
    score: -1
    }
    }
    ]
    }

    $facet

    {
    allDocs: [],
    totalCount: [
    {
    $group: {
    _id: "$source",
    firstCount: { $first: "$source_count" }
    }
    },
    {
    $project: {
    totalCount: {
    $sum: "$firstCount"
    }
    }
    }
    ]
    }

    If you enabled Auto Preview, MongoDB Compass displays the following documents next to the $project pipeline stage:

    allDocs: Array (6)
    0: Object
    name: "XLR8 Mobile"
    number_of_employees: 21
    founded_year: 2006
    score: 3.33040714263916
    source: "companies"
    source_count: 52
    1: Object
    name: "Pulse Mobile"
    number_of_employees: null
    founded_year: null
    score: 3.33040714263916
    source: "companies"
    source_count: 52
    2: Object
    name: "T-Mobile"
    number_of_employees: null
    founded_year: null
    score: 3.33040714263916
    source: "companies"
    source_count: 52
    3: Object
    business_name: "T. MOBILE"
    address: Object
    score: 2.900916337966919
    source: "inspections"
    source_count: 456
    4: Object
    business_name: "BOOST MOBILE"
    address: Object
    score: 2.900916337966919
    source: "inspections"
    source_count: 456
    5: Object
    business_name: "SPRING MOBILE"
    address: Object
    score: 2.900916337966919
    source: "inspections"
    source_count: 456
    totalCount: Array (2)
    0: Object
    _id: "companies"
    totalCount: 52
    1: Object
    _id: "inspections"
    totalCount: 456
4

MongoDB Compass might not display all the fields inside objects and all the values inside arrays for the documents it returns in the results. To view all the fields and values, expand the field in the results.

1
  1. Create a new directory called search-with-unionwith and initialize your project with the dotnet new command.

    mkdir search-with-unionwith
    cd search-with-unionwith
    dotnet new console
  2. Add the .NET/C# Driver to your project as a dependency.

    dotnet add package MongoDB.Driver
2

The following query searches both the companies and inspections collections for the term mobile in the name and business_name fields respectively.

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $set stage to add a new field named source that identifies the collection of the output documents.

    • $limit stage to limit the output to 3 results from each collection.

    • $project stage to:

      • Include only the specified fields in the results.

      • Add a field named score.

1using MongoDB.Bson;
2using MongoDB.Driver;
3using MongoDB.Driver.Search;
4
5public class Program
6{
7 public static void Main(string[] args)
8 {
9 // connect to your Atlas cluster
10 string connectionString = "<connection-string>";
11 var client = new MongoClient(connectionString);
12
13 // define namespace
14 var database = client.GetDatabase("sample_training");
15 var collection = database.GetCollection<BsonDocument>("companies");
16
17 // define pipeline stage
18 var searchStage1 = new BsonDocument("$search", new BsonDocument{{ "text", new BsonDocument
19 {{ "query", "Mobile" },{ "path", "name" }}
20 }});
21 var projectStage1 = new BsonDocument("$project", new BsonDocument{
22 { "score", new BsonDocument("$meta", "searchScore") },
23 { "_id", 0 },{ "number_of_employees", 1 },{ "founded_year", 1 },{ "name", 1 }
24 });
25 var setStage1 = new BsonDocument("$set", new BsonDocument{{ "source", "companies" }});
26 var limitStage1 = new BsonDocument("$limit", 3);
27
28 // define subpipeline
29 var searchStage2 = new BsonDocument("$search", new BsonDocument{{ "text", new BsonDocument
30 {{ "query", "Mobile" },{ "path", "business_name" }}
31 }});
32 var setStage2 = new BsonDocument("$set", new BsonDocument{ { "source", "inspections" } });
33 var projectStage2 = new BsonDocument("$project", new BsonDocument{
34 { "score", new BsonDocument("$meta", "searchScore") },
35 { "source", 1 }, { "_id", 0 }, { "business_name", 1 }, { "address", 1 }
36 });
37 var limitStage2 = new BsonDocument("$limit", 3);
38 var sortStage2 = new BsonDocument("$sort", new BsonDocument{{ "score", -1 }});
39 var unionWithPipeline = new List<BsonDocument>{searchStage2, setStage2, projectStage2, limitStage2, sortStage2};
40 var unionWithStage = new BsonDocument("$unionWith", new BsonDocument
41 {
42 { "coll", "inspections" },
43 { "pipeline", new BsonArray(unionWithPipeline) }
44 });
45 var aggregationPipeline = new List<BsonDocument> {searchStage1, projectStage1, setStage1, limitStage1,unionWithStage};
46
47 // run pipeline
48 var result = collection.Aggregate<BsonDocument>(aggregationPipeline).ToList();
49
50 //print results
51 foreach (var document in result)
52 {
53 Console.WriteLine(document);
54 }
55 }
56}

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $addFields stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A field name source_count that shows a count of the output documents.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $limit stage to limit the output to 3 results from each collection.

  • $set stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A new field named source_count that shows a count of the output documents.

1using MongoDB.Bson;
2using MongoDB.Driver;
3
4public class Program
5{
6 public static void Main(string[] args)
7 {
8 // connect to your Atlas cluster
9 var client = new MongoClient("<connection-string>");
10
11 // define namespace
12 var database = client.GetDatabase("sample_training");
13 var collection = database.GetCollection<BsonDocument>("companies");
14
15 // define pipeline
16 var pipeline = new BsonDocument[]
17 {
18 new BsonDocument("$search", new BsonDocument{
19 { "text", new BsonDocument{
20 { "query", "mobile" }, { "path", "name" },
21 { "score", new BsonDocument{
22 { "boost", new BsonDocument{ { "value", 1.6 } }}
23 }}
24 }}
25 }),
26 new BsonDocument("$project", new BsonDocument{
27 { "score", new BsonDocument("$meta", "searchScore") },
28 { "_id", 0 },
29 { "number_of_employees", 1 }, { "founded_year", 1 }, { "name", 1 }
30 }),
31 new BsonDocument("$addFields", new BsonDocument{
32 { "source", "companies" },
33 { "source_count", "$$SEARCH_META.count.lowerBound" }
34 }),
35 new BsonDocument("$limit", 3),
36 new BsonDocument("$unionWith", new BsonDocument{
37 { "coll", "inspections" },
38 { "pipeline", new BsonArray{
39 new BsonDocument("$search", new BsonDocument{
40 { "text", new BsonDocument{
41 { "query", "mobile" },
42 { "path", "business_name" }
43 }}
44 }),
45 new BsonDocument("$project", new BsonDocument{
46 { "score", new BsonDocument("$meta", "searchScore") },
47 { "business_name", 1 }, { "address", 1 }, { "_id", 0 }
48 }),
49 new BsonDocument("$limit", 3),
50 new BsonDocument("$set", new BsonDocument{
51 { "source", "inspections" },
52 { "source_count", "$$SEARCH_META.count.lowerBound" }
53 }),
54 new BsonDocument("$sort", new BsonDocument{
55 { "score", -1 }
56 })
57 }}
58 }),
59 new BsonDocument("$facet", new BsonDocument{
60 { "allDocs", new BsonArray() },
61 { "totalCount", new BsonArray{
62 new BsonDocument("$group", new BsonDocument{
63 { "_id", "$source" },
64 { "firstCount", new BsonDocument("$first", "$source_count") }
65 }),
66 new BsonDocument("$project", new BsonDocument{
67 { "totalCount", new BsonDocument("$sum", "$firstCount") }
68 })
69 }}
70 })
71 };
72
73 // run pipeline
74 var result = collection.Aggregate<BsonDocument>(pipeline).ToList();
75
76 //print results
77 foreach (var document in result)
78 {
79 Console.WriteLine(document);
80 }
81 }
82}
3

Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.

4
dotnet run search-with-unionwith.csproj
{ "name" : "XLR8 Mobile", "number_of_employees" : 21, "founded_year" : 2006, "score" : 2.0815043449401855, "source" : "companies" }
{ "name" : "Pulse Mobile", "number_of_employees" : null, "founded_year" : null, "score" : 2.0815043449401855, "source" : "companies" }
{ "name" : "T-Mobile", "number_of_employees" : null, "founded_year" : null, "score" : 2.0815043449401855, "source" : "companies" }
{ "business_name" : "T. MOBILE", "address" : { "city" : "BROOKLYN", "zip" : 11209, "street" : "86TH ST", "number" : 440 }, "source" : "inspections", "score" : 2.9009163379669189 }
{ "business_name" : "BOOST MOBILE", "address" : { "city" : "BRONX", "zip" : 10458, "street" : "E FORDHAM RD", "number" : 261 }, "source" : "inspections", "score" : 2.9009163379669189 }
{ "business_name" : "SPRING MOBILE", "address" : { "city" : "SOUTH RICHMOND HILL", "zip" : 11419, "street" : "LIBERTY AVE", "number" : 12207 }, "source" : "inspections", "score" : 2.9009163379669189 }
dotnet run search-with-unionwith.csproj
{
"allDocs" : [
{ "name" : "XLR8 Mobile", "number_of_employees" : 21, "founded_year" : 2006, "score" : 3.3304071426391602, "source" : "companies", "source_count" : NumberLong(52) },
{ "name" : "Pulse Mobile", "number_of_employees" : null, "founded_year" : null, "score" : 3.3304071426391602, "source" : "companies", "source_count" : NumberLong(52) },
{ "name" : "T-Mobile", "number_of_employees" : null, "founded_year" : null, "score" : 3.3304071426391602, "source" : "companies", "source_count" : NumberLong(52) },
{ "business_name" : "T. MOBILE", "address" : { "city" : "BROOKLYN", "zip" : 11209, "street" : "86TH ST", "number" : 440 }, "score" : 2.9009163379669189, "source" : "inspections", "source_count" : NumberLong(456) },
{ "business_name" : "BOOST MOBILE", "address" : { "city" : "BRONX", "zip" : 10458, "street" : "E FORDHAM RD", "number" : 261 }, "score" : 2.9009163379669189, "source" : "inspections", "source_count" : NumberLong(456) },
{ "business_name" : "SPRING MOBILE", "address" : { "city" : "SOUTH RICHMOND HILL", "zip" : 11419, "street" : "LIBERTY AVE", "number" : 12207 }, "score" : 2.9009163379669189, "source" : "inspections", "source_count" : NumberLong(456) }
],
"totalCount" : [
{ "_id" : "companies", "totalCount" : NumberLong(52) },
{ "_id" : "inspections", "totalCount" : NumberLong(456) }
]
}
1
2

The following query searches both the companies and inspections collections for the term mobile in the name and business_name fields respectively.

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $set stage to add a new field named source that identifies the collection of the output documents.

    • $limit stage to limit the output to 3 results from each collection.

    • $project stage to:

      • Include only the specified fields in the results.

      • Add a field named score.

1package main
2
3import (
4 "context"
5 "fmt"
6 "time"
7
8 "go.mongodb.org/mongo-driver/v2/bson"
9 "go.mongodb.org/mongo-driver/v2/mongo"
10 "go.mongodb.org/mongo-driver/v2/mongo/options"
11)
12
13func main() {
14 // connect to the Atlas cluster and set a maximum operation time
15 ctx := context.Background()
16 opts := options.Client().
17 SetTimeout(5 * time.Second).
18 ApplyURI("<connection-string>")
19
20 client, err := mongo.Connect(opts)
21 if err != nil {
22 panic(err)
23 }
24 defer client.Disconnect(ctx)
25
26 // set namespace
27 collection := client.Database("sample_training").Collection("companies")
28 // define pipeline
29 searchStage := bson.D{{"$search", bson.D{
30 {"text", bson.D{
31 {"query", "Mobile"}, {"path", "name"},
32 }},
33 }}}
34 projectStage := bson.D{{"$project", bson.D{
35 {"score", bson.D{{"$meta", "searchScore"}}},
36 {"_id", 0},
37 {"number_of_employees", 1},
38 {"founded_year", 1},
39 {"name", 1},
40 }}}
41 setStage := bson.D{{"$set", bson.D{{"source", "companies"}}}}
42 limitStage := bson.D{{"$limit", 5}}
43 unionWithStage := bson.D{{"$unionWith", bson.D{
44 {"coll", "inspections"},
45 {"pipeline", bson.A{
46 bson.D{{"$search", bson.D{
47 {"text", bson.D{
48 {"query", "Mobile"}, {"path", "business_name"},
49 }},
50 }}},
51 bson.D{{"$set", bson.D{{"source", "inspections"}}}},
52 bson.D{{"$project", bson.D{
53 {"score", bson.D{{"$meta", "searchScore"}}},
54 {"source", 1},
55 {"_id", 0},
56 {"business_name", 1},
57 {"address", 1},
58 }}},
59 bson.D{{"$limit", 3}},
60 bson.D{{"$sort", bson.D{{"score", -1}}}},
61 }},
62 }}}
63 // run pipeline
64 cursor, err := collection.Aggregate(ctx, mongo.Pipeline{searchStage, projectStage, setStage, limitStage, unionWithStage})
65 if err != nil {
66 panic(err)
67 }
68 // print results
69 var results []bson.D
70 if err = cursor.All(context.TODO(), &results); err != nil {
71 panic(err)
72 }
73 for _, result := range results {
74 fmt.Println(result)
75 }
76}

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $addFields stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A field name source_count that shows a count of the output documents.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $limit stage to limit the output to 3 results from each collection.

  • $set stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A new field named source_count that shows a count of the output documents.

1package main
2
3import (
4 "context"
5 "fmt"
6 "time"
7
8 "go.mongodb.org/mongo-driver/v2/bson"
9 "go.mongodb.org/mongo-driver/v2/mongo"
10 "go.mongodb.org/mongo-driver/v2/mongo/options"
11)
12
13func main() {
14 // connect to the Atlas cluster and set a maximum operation time
15 ctx := context.Background()
16 opts := options.Client().
17 SetTimeout(5 * time.Second).
18 ApplyURI("<connection-string>")
19
20 client, err := mongo.Connect(opts)
21 if err != nil {
22 panic(err)
23 }
24 defer client.Disconnect(ctx)
25 // set namespace
26 collection := client.Database("sample_training").Collection("companies")
27 // define pipeline
28 searchStage := bson.D{{"$search", bson.D{
29 {"text", bson.D{
30 {"query", "Mobile"}, {"path", "name"}, {"score", bson.D{{"boost", bson.D{{"value", 1.6}}}}},
31 }},
32 }}}
33 projectStage := bson.D{{"$project", bson.D{
34 {"score", bson.D{{"$meta", "searchScore"}}},
35 {"_id", 0},
36 {"number_of_employees", 1},
37 {"founded_year", 1},
38 {"name", 1},
39 }}}
40 addFieldsStage := bson.D{{"$set", bson.D{
41 {"source", "companies"},
42 {"source_count", "$$SEARCH_META.count.lowerBound"},
43 }}}
44 limitStage := bson.D{{"$limit", 3}}
45 unionWithStage := bson.D{{"$unionWith", bson.D{
46 {"coll", "inspections"},
47 {"pipeline", bson.A{
48 bson.D{{"$search", bson.D{
49 {"text", bson.D{
50 {"query", "mobile"}, {"path", "business_name"},
51 }},
52 }}},
53 bson.D{{"$project", bson.D{
54 {"score", bson.D{{"$meta", "searchScore"}}},
55 {"business_name", 1},
56 {"address", 1},
57 {"_id", 0},
58 }}},
59 bson.D{{"$limit", 3}},
60 bson.D{{"$set", bson.D{
61 {"source", "inspections"},
62 {"source_count", "$$SEARCH_META.count.lowerBound"},
63 }}},
64 bson.D{{"$sort", bson.D{{"score", -1}}}},
65 }},
66 }}}
67 facetStage := bson.D{{"$facet", bson.D{
68 {"allDocs", bson.A{}},
69 {"totalCount", bson.A{
70 bson.D{
71 {"$group", bson.D{
72 {"_id", "$source"},
73 {"firstCount", bson.D{{"$first", "$source_count"}}},
74 }},
75 },
76 bson.D{{"$project", bson.D{{"totalCount", bson.D{{"$sum", "$firstCount"}}}}}},
77 }},
78 }}}
79 // run pipeline
80 cursor, err := collection.Aggregate(ctx, mongo.Pipeline{searchStage, projectStage, addFieldsStage, limitStage, unionWithStage, facetStage})
81 if err != nil {
82 panic(err)
83 }
84 // print results
85 var results []bson.D
86 if err = cursor.All(context.TODO(), &results); err != nil {
87 panic(err)
88 }
89 for _, result := range results {
90 fmt.Println(result)
91 }
92}
3

Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.

4
go run search-with-unionwith-query.go
[{name XLR8 Mobile} {number_of_employees 21} {founded_year 2006} {score 3.33040714263916} {source companies} {source_count 52}]
[{name Pulse Mobile} {number_of_employees <nil>} {founded_year <nil>} {score 3.33040714263916} {source companies} {source_count 52}]
[{name T-Mobile} {number_of_employees <nil>} {founded_year <nil>} {score 3.33040714263916} {source companies} {source_count 52}]
[{business_name T. MOBILE} {address [{city BROOKLYN} {zip 11209} {street 86TH ST} {number 440}]} {score 2.900916337966919} {source inspections} {source_count 456}]
[{business_name BOOST MOBILE} {address [{city BRONX} {zip 10458} {street E FORDHAM RD} {number 261}]} {score 2.900916337966919} {source inspections} {source_count 456}]
[{business_name SPRING MOBILE} {address [{city SOUTH RICHMOND HILL} {zip 11419} {street LIBERTY AVE} {number 12207}]} {score 2.900916337966919} {source inspections} {source_count 456}]
go run search-with-unionwith-query.go
[
{allDocs [
[{name XLR8 Mobile} {number_of_employees 21} {founded_year 2006} {score 3.33040714263916} {source companies} {source_count 52}]
[{name Pulse Mobile} {number_of_employees <nil>} {founded_year <nil>} {score 3.33040714263916} {source companies} {source_count 52}]
[{name T-Mobile} {number_of_employees <nil>} {founded_year <nil>} {score 3.33040714263916} {source companies} {source_count 52}]
[{business_name T. MOBILE} {address [{city BROOKLYN} {zip 11209} {street 86TH ST} {number 440}]} {score 2.900916337966919} {source inspections} {source_count 456}]
[{business_name BOOST MOBILE} {address [{city BRONX} {zip 10458} {street E FORDHAM RD} {number 261}]} {score 2.900916337966919} {source inspections} {source_count 456}]
[{business_name SPRING MOBILE} {address [{city SOUTH RICHMOND HILL} {zip 11419} {street LIBERTY AVE} {number 12207}]} {score 2.900916337966919} {source inspections} {source_count 456}]
]}
{totalCount [
[{_id inspections} {totalCount 456}]
[{_id companies} {totalCount 52}]
]}
]
1

junit

4.11 or higher version

mongodb-driver-sync

4.3.0 or higher version

slf4j-log4j12

1.7.30 or higher version

2
3

The following query searches both the companies and inspections collections for the term mobile in the name and business_name fields respectively.

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $set stage to add a new field named source that identifies the collection of the output documents.

    • $limit stage to limit the output to 3 results from each collection.

    • $project stage to:

      • Include only the specified fields in the results.

      • Add a field named score.

1import com.mongodb.client.MongoClients;
2import com.mongodb.client.MongoClient;
3import com.mongodb.client.MongoDatabase;
4import org.bson.Document;
5import java.util.ArrayList;
6import java.util.Arrays;
7import java.util.List;
8
9public class SearchWithUnionwith {
10 public static void main(String[] args) {
11 // connect to Atlas cluster
12 try (MongoClient mongoClient = MongoClients.create("<connection-string>")) {
13 // get database name
14 MongoDatabase database = mongoClient.getDatabase("sample_training");
15 // define pipeline
16 List<Document> pipeline1 = Arrays.asList(
17 new Document("$search", new Document("text",
18 new Document("query", "Mobile")
19 .append("path", "name"))),
20 new Document("$project", new Document("score",
21 new Document("$meta", "searchScore"))
22 .append("_id", 0)
23 .append("number_of_employees", 1)
24 .append("founded_year", 1)
25 .append("name", 1)),
26 new Document("$set", new Document("source", "companies")),
27 new Document("$limit", 3)
28 );
29
30 List<Document> pipeline2 = Arrays.asList(
31 new Document("$search", new Document("text",
32 new Document("query", "Mobile")
33 .append("path", "business_name"))),
34 new Document("$set", new Document("source", "inspections")),
35 new Document("$project", new Document("score",
36 new Document("$meta", "searchScore"))
37 .append("source", 1)
38 .append("_id", 0)
39 .append("business_name", 1)
40 .append("address", 1)),
41 new Document("$limit", 3),
42 new Document("$sort", new Document("score", -1))
43 );
44
45 List<Document> unionWithStage = new ArrayList<>();
46 Document unionWith = new Document("$unionWith", new Document("coll", "inspections")
47 .append("pipeline", pipeline2));
48 unionWithStage.add(unionWith);
49
50 List<Document> finalPipeline = new ArrayList<>(pipeline1);
51 finalPipeline.addAll(unionWithStage);
52 // run pipeline and print results
53 database.getCollection("companies").aggregate(finalPipeline)
54 .forEach(doc -> System.out.println(doc.toJson()));
55 }
56 }
57}

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $addFields stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A field name source_count that shows a count of the output documents.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $limit stage to limit the output to 3 results from each collection.

  • $set stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A new field named source_count that shows a count of the output documents.

1import com.mongodb.client.MongoClients;
2import com.mongodb.client.MongoCollection;
3import com.mongodb.client.MongoClient;
4import org.bson.Document;
5
6public class SearchWithUnionwith {
7 public static void main(String[] args) {
8 // connect to Atlas cluster
9 try (MongoClient mongoClient = MongoClients.create("<connection-string>")) {
10 // define namespace
11 MongoCollection<Document> collection = mongoClient.getDatabase("sample_training").getCollection("companies");
12 // define pipeline
13 Document searchStage = new Document("$search", new Document("text",
14 new Document("query", "mobile")
15 .append("path", "name")
16 .append("score", new Document("boost", new Document("value", 1.6)))
17 )
18 );
19
20 Document projectStage = new Document("$project", new Document("score", new Document("$meta", "searchScore"))
21 .append("_id", 0)
22 .append("number_of_employees", 1)
23 .append("founded_year", 1)
24 .append("name", 1)
25 );
26
27 Document addFieldsStage = new Document("$addFields", new Document("source", "companies")
28 .append("source_count", "$$SEARCH_META.count.lowerBound")
29 );
30
31 Document limitStage = new Document("$limit", 3);
32
33 Document unionWithStage = new Document("$unionWith", new Document("coll", "inspections")
34 .append("pipeline", java.util.Arrays.asList(
35 new Document("$search", new Document("text",
36 new Document("query", "mobile")
37 .append("path", "business_name")
38 )),
39 new Document("$project", new Document("score", new Document("$meta", "searchScore"))
40 .append("business_name", 1)
41 .append("address", 1)
42 .append("_id", 0)
43 ),
44 new Document("$limit", 3),
45 new Document("$set", new Document("source", "inspections")
46 .append("source_count", "$$SEARCH_META.count.lowerBound")
47 ),
48 new Document("$sort", new Document("score", -1))
49 ))
50 );
51
52 Document facetStage = new Document("$facet", new Document("allDocs", java.util.Arrays.asList())
53 .append("totalCount", java.util.Arrays.asList(
54 new Document("$group", new Document("_id", "$source")
55 .append("firstCount", new Document("$first", "$source_count"))
56 ),
57 new Document("$project", new Document("totalCount",
58 new Document("$sum", "$firstCount")
59 ))
60 ))
61 );
62 // run pipeline and print results
63 collection.aggregate(java.util.Arrays.asList(
64 searchStage, projectStage, addFieldsStage, limitStage, unionWithStage, facetStage
65 )).forEach(doc -> System.out.println(doc.toJson()));
66 }
67 }
68}

Note

To run the sample code in your Maven environment, add the following code above the import statements in your file.

package com.mongodb.drivers;
4

Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.

5
javac SearchWithUnionwithQuery.java
java SearchWithUnionwithQuery
{"name": "XLR8 Mobile", "number_of_employees": 21, "founded_year": 2006, "score": 2.0815043449401855, "source": "companies"}
{"name": "Pulse Mobile", "number_of_employees": null, "founded_year": null, "score": 2.0815043449401855, "source": "companies"}
{"name": "T-Mobile", "number_of_employees": null, "founded_year": null, "score": 2.0815043449401855, "source": "companies"}
{"business_name": "T. MOBILE", "address": {"city": "BROOKLYN", "zip": 11209, "street": "86TH ST", "number": 440}, "source": "inspections", "score": 2.900916337966919}
{"business_name": "BOOST MOBILE", "address": {"city": "BRONX", "zip": 10458, "street": "E FORDHAM RD", "number": 261}, "source": "inspections", "score": 2.900916337966919}
{"business_name": "SPRING MOBILE", "address": {"city": "SOUTH RICHMOND HILL", "zip": 11419, "street": "LIBERTY AVE", "number": 12207}, "source": "inspections", "score": 2.900916337966919}
javac SearchWithUnionwithQuery.java
java SearchWithUnionwithQuery
{
"allDocs": [
{"name": "XLR8 Mobile", "number_of_employees": 21, "founded_year": 2006, "score": 3.33040714263916, "source": "companies", "source_count": 52},
{"name": "Pulse Mobile", "number_of_employees": null, "founded_year": null, "score": 3.33040714263916, "source": "companies", "source_count": 52},
{"name": "T-Mobile", "number_of_employees": null, "founded_year": null, "score": 3.33040714263916, "source": "companies", "source_count": 52},
{"business_name": "T. MOBILE", "address": {"city": "BROOKLYN", "zip": 11209, "street": "86TH ST", "number": 440}, "score": 2.900916337966919, "source": "inspections", "source_count": 456},
{"business_name": "BOOST MOBILE", "address": {"city": "BRONX", "zip": 10458, "street": "E FORDHAM RD", "number": 261}, "score": 2.900916337966919, "source": "inspections", "source_count": 456},
{"business_name": "SPRING MOBILE", "address": {"city": "SOUTH RICHMOND HILL", "zip": 11419, "street": "LIBERTY AVE", "number": 12207}, "score": 2.900916337966919, "source": "inspections", "source_count": 456}
],
"totalCount": [
{"_id": "companies", "totalCount": 52},
{"_id": "inspections", "totalCount": 456}
]
}
1

mongodb-driver-kotlin-coroutine

4.10.0 or higher version

2
3

The following query searches both the companies and inspections collections for the term mobile in the name and business_name fields respectively.

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $set stage to add a new field named source that identifies the collection of the output documents.

    • $limit stage to limit the output to 3 results from each collection.

    • $project stage to:

      • Include only the specified fields in the results.

      • Add a field named score.

1import com.mongodb.kotlin.client.coroutine.MongoClient
2import kotlinx.coroutines.runBlocking
3import org.bson.Document
4
5fun main() {
6 // connect to Atlas cluster
7 val uri = "<connection-string>"
8 val mongoClient = MongoClient.create(uri)
9
10 // set namespace
11 val database = mongoClient.getDatabase("sample_training")
12 val collection = database.getCollection<Document>("companies")
13
14 runBlocking {
15 // define pipeline
16 val pipeline1 = listOf(
17 Document("\$search", Document("text",
18 Document("query", "Mobile")
19 .append("path", "name"))), Document("\$project", Document("score",
20 Document("\$meta", "searchScore"))
21 .append("_id", 0)
22 .append("number_of_employees", 1)
23 .append("founded_year", 1)
24 .append("name", 1)), Document("\$set", Document("source", "companies")),
25 Document("\$limit", 3)
26 )
27
28 val pipeline2 = listOf(
29 Document(
30 "\$search", Document(
31 "text",
32 Document("query", "Mobile")
33 .append("path", "business_name")
34 )
35 ),
36 Document("\$set", Document("source", "inspections")),
37 Document(
38 "\$project", Document(
39 "score",
40 Document("\$meta", "searchScore")
41 )
42 .append("source", 1)
43 .append("_id", 0)
44 .append("business_name", 1)
45 .append("address", 1)
46 ),
47 Document("\$limit", 3),
48 Document("\$sort", Document("score", -1))
49 )
50
51 val unionWithStage: MutableList<Document> = ArrayList()
52 val unionWith = Document(
53 "\$unionWith", Document("coll", "inspections")
54 .append("pipeline", pipeline2)
55 )
56 unionWithStage.add(unionWith)
57 val finalPipeline: MutableList<Document> = ArrayList(pipeline1)
58 finalPipeline.addAll(unionWithStage)
59
60 // run pipeline and print results
61 val resultsFlow = collection.aggregate<Document>(finalPipeline)
62 resultsFlow.collect { println(it) }
63
64 }
65 mongoClient.close()
66}

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $addFields stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A field name source_count that shows a count of the output documents.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $limit stage to limit the output to 3 results from each collection.

  • $set stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A new field named source_count that shows a count of the output documents.

1import com.mongodb.kotlin.client.coroutine.MongoClient
2import kotlinx.coroutines.runBlocking
3import org.bson.Document
4import java.util.*
5
6fun main() {
7 // connect to Atlas cluster
8 val uri = "<connection-string>"
9 val mongoClient = MongoClient.create(uri)
10
11 // set namespace
12 val database = mongoClient.getDatabase("sample_training")
13 val collection = database.getCollection<Document>("companies")
14
15 runBlocking {
16 // define pipeline stages
17 val searchStage = Document(
18 "\$search", Document(
19 "text",
20 Document("query", "mobile")
21 .append("path", "name")
22 .append("score", Document("boost", Document("value", 1.6)))
23 )
24 )
25
26 val projectStage = Document(
27 "\$project", Document("score", Document("\$meta", "searchScore"))
28 .append("_id", 0)
29 .append("number_of_employees", 1)
30 .append("founded_year", 1)
31 .append("name", 1)
32 )
33
34 val addFieldsStage = Document(
35 "\$addFields", Document("source", "companies")
36 .append("source_count", "$\$SEARCH_META.count.lowerBound")
37 )
38
39 val limitStage = Document("\$limit", 3)
40
41 val unionWithStage = Document(
42 "\$unionWith", Document("coll", "inspections")
43 .append(
44 "pipeline", Arrays.asList(
45 Document(
46 "\$search", Document(
47 "text",
48 Document("query", "mobile")
49 .append("path", "business_name")
50 )
51 ),
52 Document(
53 "\$project", Document("score", Document("\$meta", "searchScore"))
54 .append("business_name", 1)
55 .append("address", 1)
56 .append("_id", 0)
57 ),
58 Document("\$limit", 3),
59 Document(
60 "\$set", Document("source", "inspections")
61 .append("source_count", "$\$SEARCH_META.count.lowerBound")
62 ),
63 Document("\$sort", Document("score", -1))
64 )
65 )
66 )
67
68 val facetStage = Document(
69 "\$facet", Document("allDocs", Arrays.asList<Any>())
70 .append(
71 "totalCount", Arrays.asList(
72 Document(
73 "\$group", Document("_id", "\$source")
74 .append("firstCount", Document("\$first", "\$source_count"))
75 ),
76 Document(
77 "\$project", Document(
78 "totalCount",
79 Document("\$sum", "\$firstCount")
80 )
81 )
82 )
83 )
84 )
85
86 // run pipeline and print results
87 val resultsFlow = collection.aggregate<Document>(
88 listOf(
89 searchStage,
90 projectStage,
91 addFieldsStage,
92 limitStage,
93 unionWithStage,
94 facetStage
95 )
96 )
97 resultsFlow.collect { println(it) }
98
99 }
100 mongoClient.close()
101}
4

Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.

5

When you run the SearchWithUnionwithQuery.kt program in your IDE, it prints the following documents:

Document{{name=XLR8 Mobile, number_of_employees=21, founded_year=2006, score=2.0815043449401855, source=companies}}
Document{{name=Pulse Mobile, number_of_employees=null, founded_year=null, score=2.0815043449401855, source=companies}}
Document{{name=Mobile Trend, number_of_employees=null, founded_year=2003, score=2.0815043449401855, source=companies}}
Document{{business_name=T-MOBILE, address=Document{{city=BROOKLYN, zip=11229, street=AVENUE U, number=1616}}, source=inspections, score=2.900916337966919}}
Document{{business_name=BOOST MOBILE, address=Document{{city=BRONX, zip=10458, street=E FORDHAM RD, number=261}}, source=inspections, score=2.900916337966919}}
Document{{business_name=SPRING MOBILE, address=Document{{city=SOUTH RICHMOND HILL, zip=11419, street=LIBERTY AVE, number=12207}}, source=inspections, score=2.900916337966919}}

When you run the SearchWithUnionwithQuery.kt program in your IDE, it prints the following result:

Document{{allDocs=[Document{{name=XLR8 Mobile,
number_of_employees=21, founded_year=2006,
score=3.33040714263916, source=companies,
source_count=52}}, Document{{name=Pulse Mobile,
number_of_employees=null, founded_year=null,
score=3.33040714263916, source=companies,
source_count=52}}, Document{{name=Mobile Trend,
number_of_employees=null, founded_year=2003,
score=3.33040714263916, source=companies,
source_count=52}}, Document{{business_name=T-MOBILE,
address=Document{{city=BROOKLYN, zip=11229, street=AVENUE
U, number=1616}}, score=2.900916337966919,
source=inspections, source_count=456}},
Document{{business_name=BOOST MOBILE,
address=Document{{city=BRONX, zip=10458, street=E FORDHAM
RD, number=261}}, score=2.900916337966919,
source=inspections, source_count=456}},
Document{{business_name=SPRING MOBILE,
address=Document{{city=SOUTH RICHMOND HILL, zip=11419,
street=LIBERTY AVE, number=12207}},
score=2.900916337966919, source=inspections,
source_count=456}}],
totalCount=[Document{{_id=inspections, totalCount=456}},
Document{{_id=companies, totalCount=52}}]}}
1
2

The following query searches both the companies and inspections collections for the term mobile in the name and business_name fields respectively.

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $set stage to add a new field named source that identifies the collection of the output documents.

    • $limit stage to limit the output to 3 results from each collection.

    • $project stage to:

      • Include only the specified fields in the results.

      • Add a field named score.

1const MongoClient = require("mongodb").MongoClient;
2const assert = require("assert");
3
4const agg = [
5 {
6 '$search': {
7 'text': { 'query': 'Mobile', 'path': 'name' }
8 }
9 }, {
10 '$project': {
11 'score': { '$meta': 'searchScore' },
12 '_id': 0, 'number_of_employees': 1, 'founded_year': 1, 'name': 1
13 }
14 }, {
15 '$set': { 'source': 'companies' }
16 }, {
17 '$limit': 3
18 }, {
19 '$unionWith': {
20 'coll': 'inspections',
21 'pipeline': [
22 {
23 '$search': {
24 'text': { 'query': 'Mobile', 'path': 'business_name' }
25 }
26 }, {
27 '$set': { 'source': 'inspections' }
28 }, {
29 '$project': {
30 'score': { '$meta': 'searchScore' },
31 'source': 1, '_id': 0, 'business_name': 1, 'address': 1
32 }
33 }, {
34 '$limit': 3
35 }, {
36 '$sort': { 'score': -1 }
37 }
38 ]
39 }
40 }
41 ];
42
43MongoClient.connect(
44 "<connection-string>",
45 { useNewUrlParser: true, useUnifiedTopology: true },
46 async function (connectErr, client) {
47 assert.equal(null, connectErr);
48 const coll = client.db("sample_training").collection("companies");
49 let cursor = await coll.aggregate(agg);
50 await cursor.forEach((doc) => console.log(doc));
51 client.close();
52 }
53);

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $addFields stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A field name source_count that shows a count of the output documents.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $limit stage to limit the output to 3 results from each collection.

  • $set stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A new field named source_count that shows a count of the output documents.

1const MongoClient = require("mongodb").MongoClient;
2const assert = require("assert");
3
4const agg = [
5 {'$search': { 'text': {
6 'query': 'mobile',
7 'path': 'name',
8 'score': {
9 'boost': { 'value': 1.6 }
10 }
11 }}},
12 {'$project': {
13 'score': { '$meta': 'searchScore' },
14 '_id': 0,
15 'number_of_employees': 1,
16 'founded_year': 1,
17 'name': 1
18 }},
19 {'$addFields': {
20 'source': 'companies',
21 'source_count': '$$SEARCH_META.count.lowerBound'
22 }},
23 {'$limit': 3},
24 {'$unionWith': {
25 'coll': 'inspections',
26 'pipeline': [
27 {'$search': {
28 'text': { 'query': 'mobile', 'path': 'business_name' }
29 }},
30 {'$project': {
31 'score': { '$meta': 'searchScore' },
32 'business_name': 1,
33 'address': 1,
34 '_id': 0
35 }},
36 {'$limit': 3},
37 {'$set': {
38 'source': 'inspections',
39 'source_count': '$$SEARCH_META.count.lowerBound'
40 }},
41 {'$sort': { 'score': -1 } }
42 ]
43 }},
44 {'$facet': {
45 'allDocs': [],
46 'totalCount': [
47 {'$group': {
48 '_id': '$source',
49 'firstCount': { '$first': '$source_count' }
50 }},
51 {'$project': {
52 'totalCount': { '$sum': '$firstCount' }
53 }}
54 ]
55 }}
56];
57
58MongoClient.connect(
59 "<connection-string>",
60 { useNewUrlParser: true, useUnifiedTopology: true },
61 async function (connectErr, client) {
62 assert.equal(null, connectErr);
63 const coll = client.db("sample_training").collection("companies");
64 let cursor = await coll.aggregate(agg);
65 await cursor.forEach((doc) => console.log(doc));
66 client.close();
67 }
68);
3

Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.

4

Run the following command to query your collection:

node unionwith-with-search-query.js
{
name: 'SoftBank Mobile',
number_of_employees: null,
founded_year: null,
score: 2.0815043449401855,
source: 'companies'
}
{
name: 'Mobile Factory',
number_of_employees: 53,
founded_year: 2001,
score: 2.0815043449401855,
source: 'companies'
}
{
name: 'ZOOZ Mobile',
number_of_employees: 5,
founded_year: 2008,
score: 2.0815043449401855,
source: 'companies'
}
{
business_name: 'T. MOBILE',
address: { city: 'BROOKLYN', zip: 11209, street: '86TH ST', number: 440 },
source: 'inspections',
score: 2.900916337966919
}
{
business_name: 'BOOST MOBILE',
address: { city: 'BRONX', zip: 10458, street: 'E FORDHAM RD', number: 261 },
source: 'inspections',
score: 2.900916337966919
}
{
business_name: 'T-MOBILE',
address: { city: 'BROOKLYN', zip: 11229, street: 'AVENUE U', number: 1616 },
source: 'inspections',
score: 2.900916337966919
}
node unionwith-with-search-query.js
{
allDocs: [
{
name: 'XLR8 Mobile',
number_of_employees: 21,
founded_year: 2006,
score: 3.33040714263916,
source: 'companies',
source_count: 52
},
{
name: 'Pulse Mobile',
number_of_employees: null,
founded_year: null,
score: 3.33040714263916,
source: 'companies',
source_count: 52
},
{
name: 'T-Mobile',
number_of_employees: null,
founded_year: null,
score: 3.33040714263916,
source: 'companies',
source_count: 52
},
{
business_name: 'T. MOBILE',
address: [Object],
score: 2.900916337966919,
source: 'inspections',
source_count: 456
},
{
business_name: 'BOOST MOBILE',
address: [Object],
score: 2.900916337966919,
source: 'inspections',
source_count: 456
},
{
business_name: 'SPRING MOBILE',
address: [Object],
score: 2.900916337966919,
source: 'inspections',
source_count: 456
}
],
totalCount: [
{ _id: 'companies', totalCount: 52 },
{ _id: 'inspections', totalCount: 456 }
]
}
1
2

The following query searches both the companies and inspections collections for the term mobile in the name and business_name fields respectively.

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $set stage to add a new field named source that identifies the collection of the output documents.

    • $limit stage to limit the output to 3 results from each collection.

    • $project stage to:

      • Include only the specified fields in the results.

      • Add a field named score.

1import pymongo
2import dns
3
4client = pymongo.MongoClient('<connection-string>')
5result = client['sample_training']['companies'].aggregate([
6 {
7 '$search': {
8 'text': { 'query': 'Mobile', 'path': 'name' }
9 }
10 }, {
11 '$project': {
12 'score': { '$meta': 'searchScore' }, '_id': 0, 'number_of_employees': 1, 'founded_year': 1, 'name': 1
13 }
14 }, {
15 '$set': { 'source': 'companies' }
16 }, {
17 '$limit': 3
18 }, {
19 '$unionWith': {
20 'coll': 'inspections',
21 'pipeline': [
22 {
23 '$search': {
24 'text': { 'query': 'Mobile', 'path': 'business_name' }
25 }
26 }, {
27 '$set': { 'source': 'inspections' }
28 }, {
29 '$project': {
30 'score': { '$meta': 'searchScore' }, 'source': 1, '_id': 0, 'business_name': 1, 'address': 1
31 }
32 }, {
33 '$limit': 3
34 }, {
35 '$sort': { 'score': -1 }
36 }
37 ]
38 }
39 }
40])
41
42for i in result:
43 print(i)

This query uses the following stages:

  • $search to search for companies that include mobile in the name.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $addFields stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A field name source_count that shows a count of the output documents.

  • $unionWith to do the following:

    • Use $search stage in the sub-pipeline to search for inspections of companies that include mobile in the name.

    • Perform a union of documents from the companies and documents from the inspections collections.

  • $project stage to:

    • Include only the specified fields in the results.

    • Add a field named score.

  • $limit stage to limit the output to 3 results from each collection.

  • $set stage to add the following new fields:

    • A new field named source that identifies the collection of the output documents.

    • A new field named source_count that shows a count of the output documents.

1import pymongo
2import dns
3
4client = pymongo.MongoClient('<connection-string>')
5result = client['sample_training']['companies'].aggregate([
6 {'$search': { 'text': {
7 'query': 'mobile',
8 'path': 'name',
9 'score': { 'boost': { 'value': 1.6 } }
10 }}},
11 {'$project': {
12 'score': { '$meta': 'searchScore' },
13 '_id': 0,
14 'number_of_employees': 1,
15 'founded_year': 1,
16 'name': 1
17 }},
18 {'$addFields': {
19 'source': 'companies',
20 'source_count': '$$SEARCH_META.count.lowerBound'
21 }},
22 {'$limit': 3},
23 {'$unionWith': {
24 'coll': 'inspections',
25 'pipeline': [
26 {'$search': { 'text': {
27 'query': 'mobile',
28 'path': 'business_name'
29 }} },
30 {'$project': {
31 'score': { '$meta': 'searchScore' },
32 'business_name': 1,
33 'address': 1,
34 '_id': 0
35 }},
36 {'$limit': 3},
37 {'$set': {
38 'source': 'inspections',
39 'source_count': '$$SEARCH_META.count.lowerBound'
40 }},
41 {'$sort': { 'score': -1 }}
42 ]
43 }},
44 {'$facet': {
45 'allDocs': [],
46 'totalCount': [
47 {'$group': {
48 '_id': '$source',
49 'firstCount': { '$first': '$source_count' }
50 }},
51 {'$project': {
52 'totalCount': { '$sum': '$firstCount' }
53 }}
54 ]
55 }}
56])
57
58for i in result:
59 print(i)
3

Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.

4
python search-with-unionwith-query.py
{'name': 'XLR8 Mobile', 'number_of_employees': 21, 'founded_year': 2006, 'score': 2.0815043449401855, 'source': 'companies'}
{'name': 'Pulse Mobile', 'number_of_employees': None, 'founded_year': None, 'score': 2.0815043449401855, 'source': 'companies'}
{'name': 'T-Mobile', 'number_of_employees': None, 'founded_year': None, 'score': 2.0815043449401855, 'source': 'companies'}
{'business_name': 'T. MOBILE', 'address': {'city': 'BROOKLYN', 'zip': 11209, 'street': '86TH ST', 'number': 440}, 'source': 'inspections', 'score': 2.900916337966919}
{'business_name': 'BOOST MOBILE', 'address': {'city': 'BRONX', 'zip': 10458, 'street': 'E FORDHAM RD', 'number': 261}, 'source': 'inspections', 'score': 2.900916337966919}
{'business_name': 'SPRING MOBILE', 'address': {'city': 'SOUTH RICHMOND HILL', 'zip': 11419, 'street': 'LIBERTY AVE', 'number': 12207}, 'source': 'inspections', 'score': 2.900916337966919}
python search-with-unionwith-query.py
{
'allDocs': [
{'name': 'XLR8 Mobile', 'number_of_employees': 21, 'founded_year': 2006, 'score': 3.33040714263916, 'source': 'companies', 'source_count': 52},
{'name': 'Pulse Mobile', 'number_of_employees': None, 'founded_year': None, 'score': 3.33040714263916, 'source': 'companies', 'source_count': 52},
{'name': 'T-Mobile', 'number_of_employees': None, 'founded_year': None, 'score': 3.33040714263916, 'source': 'companies', 'source_count': 52},
{'business_name': 'T. MOBILE', 'address': {'city': 'BROOKLYN', 'zip': 11209, 'street': '86TH ST', 'number': 440}, 'score': 2.900916337966919, 'source': 'inspections', 'source_count': 456},
{'business_name': 'BOOST MOBILE', 'address': {'city': 'BRONX', 'zip': 10458, 'street': 'E FORDHAM RD', 'number': 261}, 'score': 2.900916337966919, 'source': 'inspections', 'source_count': 456},
{'business_name': 'SPRING MOBILE', 'address': {'city': 'SOUTH RICHMOND HILL', 'zip': 11419, 'street': 'LIBERTY AVE', 'number': 12207}, 'score': 2.900916337966919, 'source': 'inspections', 'source_count': 456}
],
'totalCount': [
{'_id': 'companies', 'totalCount': 52},
{'_id': 'inspections', 'totalCount': 456}
]
}

This tutorial describes how to create an index and run queries against the sample_supplies.sales collection from the sample dataset and a new sample_supplies.purchaseOrders.

An on-demand materialized view is a collection that you create and update using a $merge aggregation pipeline stage. You can create an Atlas Search index on the materialized view and then run queries on the materialized view using the $search aggregation pipeline stage.

This tutorial takes you through the following steps:

  1. Create a collection named purchaseOrders in the sample_supplies database.

  2. Create two scheduled triggers:

    • updateMonthlySales, with a function named updateMonthlySales that initializes the monthlyPhoneTransactions materialized view using data from the sample sample_supplies.sales collection.

    • updateMonthlyPurchaseOrders, with a function named updateMonthlyPurchaseOrders that updates the monthlyPhoneTransactions materialized view using data from the sample_supplies.purchaseOrders collection.

  3. Create an Atlas Search index on the monthlyPhoneTransactions materialized view.

  4. Run a query on the monthlyPhoneTransactions materialized view.

1
  1. Open mongosh in a terminal window and connect to your cluster. For detailed instructions on connecting, see Connect via mongosh.

  2. Use the sample_supplies database:

    use sample_supplies
2

Add the purchaseOrders collection with new phone purchase order data from January of 2018. Run the following commands:

db.purchaseOrders.insertMany( [
{
saleDate: ISODate("2018-01-23T21:06:49.506Z"),
items: [
{
name: 'printer paper',
tags: [ 'office', 'stationary' ],
price: Decimal128("40.01"),
quantity: 2
},
{
name: 'notepad',
tags: [ 'office', 'writing', 'school' ],
price: Decimal128("35.29"),
quantity: 2
},
{
name: 'pens',
tags: [ 'writing', 'office', 'school', 'stationary' ],
price: Decimal128("56.12"),
quantity: 5
},
{
name: 'backpack',
tags: [ 'school', 'travel', 'kids' ],
price: Decimal128("77.71"),
quantity: 2
},
{
name: 'notepad',
tags: [ 'office', 'writing', 'school' ],
price: Decimal128("18.47"),
quantity: 2
},
{
name: 'envelopes',
tags: [ 'stationary', 'office', 'general' ],
price: Decimal128("19.95"),
quantity: 8
},
{
name: 'envelopes',
tags: [ 'stationary', 'office', 'general' ],
price: Decimal128("8.08"),
quantity: 3
},
{
name: 'binder',
tags: [ 'school', 'general', 'organization' ],
price: Decimal128("14.16"),
quantity: 3
}
],
storeLocation: 'Denver',
customer: {
gender: 'M',
age: 42,
email: 'cauho@witwuta.sv',
satisfaction: 4
},
couponUsed: true,
purchaseMethod: 'Phone'
}
])
db.purchaseOrders.insertMany( [
{
saleDate: ISODate("2018-01-25T10:01:02.918Z"),
items: [
{
name: 'envelopes',
tags: [ 'stationary', 'office', 'general' ],
price: Decimal128("8.05"),
quantity: 10
},
{
name: 'binder',
tags: [ 'school', 'general', 'organization' ],
price: Decimal128("28.31"),
quantity: 9
},
{
name: 'notepad',
tags: [ 'office', 'writing', 'school' ],
price: Decimal128("20.95"),
quantity: 3
},
{
name: 'laptop',
tags: [ 'electronics', 'school', 'office' ],
price: Decimal128("866.5"),
quantity: 4
},
{
name: 'notepad',
tags: [ 'office', 'writing', 'school' ],
price: Decimal128("33.09"),
quantity: 4
},
{
name: 'printer paper',
tags: [ 'office', 'stationary' ],
price: Decimal128("37.55"),
quantity: 1
},
{
name: 'backpack',
tags: [ 'school', 'travel', 'kids' ],
price: Decimal128("83.28"),
quantity: 2
},
{
name: 'pens',
tags: [ 'writing', 'office', 'school', 'stationary' ],
price: Decimal128("42.9"),
quantity: 4
},
{
name: 'envelopes',
tags: [ 'stationary', 'office', 'general' ],
price: Decimal128("16.68"),
quantity: 2
}
],
storeLocation: 'Seattle',
customer: { gender: 'M', age: 50, email: 'keecade@hem.uy', satisfaction: 5 },
couponUsed: false,
purchaseMethod: 'Phone'
}
])
3

Query the purchaseOrders collection to confirm the new purchase order entries.

db.purchaseOrders.find().sort( {saleDate: -1} )
{
_id: ObjectId("62434c07d574cd0ce200ba75"),
saleDate: ISODate("2018-01-25T10:01:02.918Z"),
items: [
{
name: 'envelopes',
tags: [ 'stationary', 'office', 'general' ],
price: Decimal128("8.05"),
quantity: 10
},
{
name: 'binder',
tags: [ 'school', 'general', 'organization' ],
price: Decimal128("28.31"),
quantity: 9
},
{
name: 'notepad',
tags: [ 'office', 'writing', 'school' ],
price: Decimal128("20.95"),
quantity: 3
},
{
name: 'laptop',
tags: [ 'electronics', 'school', 'office' ],
price: Decimal128("866.5"),
quantity: 4
},
{
name: 'notepad',
tags: [ 'office', 'writing', 'school' ],
price: Decimal128("33.09"),
quantity: 4
},
{
name: 'printer paper',
tags: [ 'office', 'stationary' ],
price: Decimal128("37.55"),
quantity: 1
},
{
name: 'backpack',
tags: [ 'school', 'travel', 'kids' ],
price: Decimal128("83.28"),
quantity: 2
},
{
name: 'pens',
tags: [ 'writing', 'office', 'school', 'stationary' ],
price: Decimal128("42.9"),
quantity: 4
},
{
name: 'envelopes',
tags: [ 'stationary', 'office', 'general' ],
price: Decimal128("16.68"),
quantity: 2
}
],
storeLocation: 'Seattle',
customer: {
gender: 'M',
age: 50,
email: 'keecade@hem.uy',
satisfaction: 5
},
couponUsed: false,
purchaseMethod: 'Phone'
},
{
_id: ObjectId("62434c07d574cd0ce200ba74"),
saleDate: ISODate("2018-01-23T21:06:49.506Z"),
items: [
{
name: 'printer paper',
tags: [ 'office', 'stationary' ],
price: Decimal128("40.01"),
quantity: 2
},
{
name: 'notepad',
tags: [ 'office', 'writing', 'school' ],
price: Decimal128("35.29"),
quantity: 2
},
{
name: 'pens',
tags: [ 'writing', 'office', 'school', 'stationary' ],
price: Decimal128("56.12"),
quantity: 5
},
{
name: 'backpack',
tags: [ 'school', 'travel', 'kids' ],
price: Decimal128("77.71"),
quantity: 2
},
{
name: 'notepad',
tags: [ 'office', 'writing', 'school' ],
price: Decimal128("18.47"),
quantity: 2
},
{
name: 'envelopes',
tags: [ 'stationary', 'office', 'general' ],
price: Decimal128("19.95"),
quantity: 8
},
{
name: 'envelopes',
tags: [ 'stationary', 'office', 'general' ],
price: Decimal128("8.08"),
quantity: 3
},
{
name: 'binder',
tags: [ 'school', 'general', 'organization' ],
price: Decimal128("14.16"),
quantity: 3
}
],
storeLocation: 'Denver',
customer: {
gender: 'M',
age: 42,
email: 'cauho@witwuta.sv',
satisfaction: 4
},
couponUsed: true,
purchaseMethod: 'Phone'
}

The two query results reflect that the purchase order data ends in January of 2018.

Note

To create the triggers, you must have Project Owner or higher access to the project.

In the following procedures, you create triggers to create a materialized view and schedule a function to update the materialized view daily. Expand the following sections to view the steps for each trigger:

Create an Atlas Search index on the monthlyPhoneTransactions collection.

1

Warning

Navigation Improvements In Progress

We're currently rolling out a new and improved navigation experience. If the following steps don't match your view in the Atlas UI, see the preview documentation.

  1. If it's not already displayed, select the organization that contains your desired project from the Organizations menu in the navigation bar.

  2. If it's not already displayed, select your desired project from the Projects menu in the navigation bar.

  3. If it's not already displayed, click Clusters in the sidebar.

    The Clusters page displays.

2

You can go the Atlas Search page from the sidebar, the Data Explorer, or your cluster details page.

  1. In the sidebar, click Atlas Search under the Services heading.

    If you have no clusters, click Create cluster to create one. To learn more, see Create a Cluster.

  2. If your project has multiple clusters, select the cluster you want to use from the Select cluster dropdown, then click Go to Atlas Search.

    The Atlas Search page displays.

  1. Click the Browse Collections button for your cluster.

  2. Expand the database and select the collection.

  3. Click the Search Indexes tab for the collection.

    The Atlas Search page displays.

  1. Click the cluster's name.

  2. Click the Atlas Search tab.

    The Atlas Search page displays.

3
4

Make the following selections on the page and then click Next.

Search Type

Select the Atlas Search index type.

Index Name and Data Source

Specify the following information:

  • Index Name: monthlyPhoneTransactions

  • Database and Collection:

    • sample_supplies database

    • monthlyPhoneTransactions collection

Configuration Method

For a guided experience, select Visual Editor.

To edit the raw index definition, select JSON Editor.

Note

Your Atlas Search index is named default by default. If you keep this name, then your index will be the default Search index for any Atlas Search query that does not specify a different index option in its operators. If you are creating multiple indexes, we recommend that you maintain a consistent, descriptive naming convention across your indexes.

5
6
7

A modal window appears to let you know your index is building. Click the Close button.

8

The newly created index appears on the Atlas Search tab. While the index is building, the Status field reads Building. When the index is finished building, the Status field reads Active.

Note

Larger collections take longer to index. You will receive an email notification when your index is finished building.

Run a query against the newly updated and indexed monthlyPhoneTransactions collection.

1

Open mongosh in a terminal window and connect to your cluster. For detailed instructions on connecting, see Connect via mongosh.

2

Run the following command at mongosh prompt:

use sample_supplies
3

The following query counts the number of months in monthlyPhoneTransactions with total sales greater than or equal to 10000 dollars:

db.monthlyPhoneTransactions.aggregate([
{
$search: {
"index": "monthlySalesIndex",
"range": {
"gt": 10000,
"path": ["sales_price"]
}
}
},
{
$count: 'months_w_over_10000'
},
])

The above query returns 4, indicating that only 4 months out of all the months in the monthlyPhoneTransactions materialized view had total sales greater than or equal to 10000 dollars. This result reflects data from both the sample_supplies.sales and sample_supplies.purchaseOrders collections.

For complete aggregation pipeline documentation, see the MongoDB Server Manual.

Back

Embedded Documents