Spring Boot MongoDB Lookup not working with ObjectId - mongodb

I've user collection which has role object which has roleId. I also have roles collection which has id.
Now,for each role, I'd like to get the list of users.
Ex:
[
{
"name": "Scott",
"role": {
"roleId": "123432"
}
},
{
"name": "John",
"role": {
"roleId": "123432"
}
},
{
"name": "Scott",
"role": {
"roleId": "556432"
}
}
]
Roles Data:
[
{
"id": "123432"
"name": "admin",
"type": "internal"
},
{
"id": "556432"
"name": "owner",
"type": "external"
},
{
"id": "556432"
"name": "owner",
"type": "internal"
}
]
Now I want to get all the roles of type internal and their related users:
So, the output should be,
[
{
"role": "123432",
"users": [
{
"name": "Scott",
"role": {
"roleId": "123432"
}
},
{
"name": "John",
"role": {
"roleId": "123432"
}
}
],
{
"role": "556432",
"users": []
}
}
]
This is my aggregation in SpringBoort:
LookupOperation lookupOperation = LookupOperation.newLookup().from("roles").localField("roleId")
.foreignField("_id").as("roles");
AggregationOperation match = Aggregation.match(Criteria.where("type").is("internal"));
Aggregation aggregation = Aggregation.newAggregation(lookupOperation, match);
List<UserDTO> results = mongoTemplate.aggregate(aggregation, "users", UserDTO.class).getMappedResults();
This is working great when roleId is in the form of ObjectId(Ex: ObjectId("556432")). But it's not working if it's in String(Ex: "556432").
Can someone help me on this please?

Related

How to get values with filter depends on other collection in MongoDB

I have 2 collectionsEmployee and Role. Now I want to get all name from Employee without title software engineer in collection Role. The valid answer for example below is [Lisa, Nick]. How to solve this problem. Thank you so much.
Employee
[
{
"id": "001",
"name": "John"
},
{
"id": "002",
"name": "Lisa"
},
{
"id": "003",
"name": "Zery"
},
{
"id": "004",
"name": "Nick"
}
]
Role
[
{
"employee_id": "001",
"title": "software engineer"
},
{
"employee_id": "001",
"title": "data scientist"
},
{
"employee_id": "002",
"title": "data engineer"
},
{
"employee_id": "002",
"title": "data scientist"
},
{
"employee_id": "002",
"title": "data analyst"
},
{
"employee_id": "003",
"title": "software engineer"
}
]
Here's one way you could do it.
db.Employees.aggregate([
{
"$lookup": {
"from": "Roles",
"localField": "id",
"foreignField": "employee_id",
"as": "roles"
}
},
{
"$match": {
"roles.title": {
"$nin": ["software engineer"]
}
}
},
{
"$project": {
"_id": 0,
"name": 1
}
}
])
Try it on mongoplayground.net.

MongoDB lookup with multiple nested levels

In my application, I have a section of comments and replies under some documents.
Here's how my database schema looks like
db.updates.insertOne({
"_id": "62347813d28412ffd82b551d",
"documentID": "17987e64-f848-40f3-817e-98adfd9f4ecd",
"stream": [
{
"id": "623478134c449b218b68f636",
"type": "comment",
"text": "Hey #john, we got a problem",
"authorID": "843df3dbbdfc62ba2d902326",
"taggedUsers": [
"623209d2ab26cfdbbd3fd348"
],
"replies": [
{
"id": "623478284c449b218b68f637",
"type": "reply",
"text": "Not sure, let's involve #jim here",
"authorID": "623209d2ab26cfdbbd3fd348",
"taggedUsers": [
"26cfdbbd3fd349623209d2ab"
]
}
]
}
]
})
db.users.insertMany([
{
"_id": "843df3dbbdfc62ba2d902326",
"name": "Manager"
},
{
"_id": "623209d2ab26cfdbbd3fd348",
"name": "John"
},
{
"_id": "26cfdbbd3fd349623209d2ab",
"name": "Jim"
},
])
I want to join those two collections, and replace user ids with complete user information on all levels. So the final JSON should look like this
{
"_id": "62347813d28412ffd82b551d",
"documentID": "17987e64-f848-40f3-817e-98adfd9f4ecd",
"stream": [
{
"id": "623478134c449b218b68f636",
"type": "comment",
"text": "Hey #john, we got a problem",
"author": {
"_id": "843df3dbbdfc62ba2d902326",
"name": "Manager"
},
"taggedUsers": [
{
"_id": "623209d2ab26cfdbbd3fd348",
"name": "John"
}
],
"replies": [
{
"id": "623478284c449b218b68f637",
"type": "reply",
"text": "Not sure, let's involve #jim here",
"author": {
"_id": "623209d2ab26cfdbbd3fd348",
"name": "John"
},
"taggedUsers": [
{
"_id": "26cfdbbd3fd349623209d2ab",
"name": "Jim"
}
]
}
]
}
]
}
I know how to do the $lookup on the top-level fields, including pipelines, but how can I do with the nested ones?

Unable to aggregate multiple collections

I've user collection which has role object which has roleId. I also have roles collection which has id.
Now,for each role, I'd like to get the list of users.
Ex:
[
{
"name": "Scott",
"role": {
"roleId": "123432"
}
},
{
"name": "John",
"role": {
"roleId": "123432"
}
},
{
"name": "Scott",
"role": {
"roleId": "556432"
}
}
]
Roles Data:
[
{
"id": "123432"
"name": "admin",
"type": "internal"
},
{
"id": "556432"
"name": "owner",
"type": "external"
},
{
"id": "556432"
"name": "owner",
"type": "internal"
}
]
Now I want to get all the roles of type internal and their related users:
So, the output should be,
[
{
"role": "123432",
"users": [
{
"name": "Scott",
"role": {
"roleId": "123432"
}
},
{
"name": "John",
"role": {
"roleId": "123432"
}
}
],
{
"role": "556432",
"users": []
}
}
]
I'm doing this with Spring Boot.if someone can help me on how to get this aggregation using spring boot mongo, that'd be very helpful for me. Thank you so much.
Execute aggregate on your role collection and first filter out role as per your condition. Since you want all internal roles, your match stage should be:
{
$match: {
"type": "internal"
}
}
Now its time to lookup users for each role:
{
$lookup: {
from: "user",
as: "users",
localField: "id",
foreignField: "role.roleId"
}
}
I don't know how mongo queries are executed on spring boot but this is how its done on mongo so you can convert it to your language specific code.
Here's a working example on mongo playground.
https://mongoplayground.net/p/I1FPuX971YZ

Loopback 3 get relation from embedded model

I'm using loopback 3 to build a backend with mongoDB.
So i have 3 models: Object, Attachment and AwsS3.
Object has a relation Embeds2Many to Attachment.
Attachment has a relation Many2One to AwsS3.
Objects look like that in mongoDB
[
{
"fieldA": "valueA1",
"attachments": [
{
"id": 1,
"awsS3Id": "1234"
},
{
"id": 2,
"awsS3Id": "1235"
}
]
},
{
"fieldA": "valueA2",
"attachments": [
{
"id": 4,
"awsS3Id": "1236"
},
{
"id": 5,
"awsS3Id": "1237"
}
]
}
]
AwsS3 looks like that in mongoDB
[
{
"id": "1",
"url": "abc.com/1"
},
{
"id": "2",
"url": "abc.com/2"
}
]
The question is: how can i get Objects included Attachment and AwsS3.url over the RestAPI?
I have try with the include and scope filter. But it didn't work. It look like, that this function is not implemented in loopback3, right? Here is what i tried over the GET request:
{
"filter": {
"include": {
"relation": "Attachment",
"scope": {
"include": {
"relation": "awsS3",
}
}
}
}
}
With this request i only got the Objects with Attachments without anything from AwsS3.
UPDATE for the relation definitons
The relation from Object to Attachment:
"Attachment": {
"type": "embedsMany",
"model": "Attachment",
"property": "attachments",
"options": {
"validate": true,
"forceId": false
}
},
The relation from Attachment to AwsS3
in attachment.json
"relations": {
"awsS3": {
"type": "belongsTo",
"model": "AwsS3",
"foreignKey": ""
}
}
in AwsS3.json
"relations": {
"attachments": {
"type": "hasMany",
"model": "Attachment",
"foreignKey": ""
}
}
Try this filter:
{ "filter": { "include": ["awsS3", "attachments"]}}}}

Design Search service using elastic search

I have a requirement. I am building up a search service for a social network. The search service should return the name of the users that somebody searches. Now it will be limited to user domain search only. I am planning to use elastic search to keep the indexes(user domain details). I will then call the EL from my search service(The search service is on nodejs). I am not able to think of a design on how to create the indexes for EL. Should I use a batch to create the indexes or during creation of users I will create the index.
A good pointers or a good design will be appreciated.
you should create index when new user create
simple example may be useful
your user data like:
`
[
{
"_id": "1",
"status": true,
"username": "mak",
"userdomain": "mydomain.com",
"name": "mak doe"
},
{
"_id": "2",
"status": true,
"username": "janny",
"userdomain": "mydomain.com",
"name": "janny"
},
{
"_id": "3",
"status": true,
"username": "mac",
"userdomain": "newdomain.com",
"name": "mac peter"
},
{
"_id": "4",
"status": true,
"username": "mak",
"userdomain": "mydomain.com",
"name": "mak peter"
},
{
"id": "5",
"status": true,
"username": "mak",
"userdomain": "newdomain.com",
"name": "mak peter"
},
]
`
elastic schema look like as below:
`
PUT socialdata
{
"mappings": {
"users": {
"properties": {
"status": {
"type": "boolean"
},
"name": {
"type": "text"
},
"username": {
"type": "string",
"fields": {
"raw": {
"type": "string",
"analyzer": "keyword_lowercase_analyzer"
},
"english": {
"type": "text",
"analyzer": "english"
}
}
},
"userdomain": {
"type": "string",
"fields": {
"raw": {
"type": "string",
"analyzer": "keyword_lowercase_analyzer"
},
"english": {
"type": "text",
"analyzer": "english"
}
}
}
}
}
}
}
`
For Bulk upload :
`
POST socialdata/users/_bulk
{ "index": { "_index": "socialdata","_type": "users", "_id": 1 }}
{"status":true,"username": "mak","userdomain": "mydomain.com","name": "mak doe"}
{ "index": { "_index": "socialdata","_type": "users", "_id": 2 }}
{"status":true,"username": "janny","userdomain": "mydomain.com","name": "janny"}
{ "index": { "_index": "socialdata","_type": "users", "_id": 3 }}
{"status":true,"username": "mac","userdomain": "newdomain.com","name": "mac peter"}
{ "index": { "_index": "socialdata","_type": "users", "_id": 4 }}
{"status":true,"username": "mak","userdomain": "mydomain.com","name": "mak peter"}
{ "index": { "_index": "socialdata","_type": "users", "_id": 5 }}
{"status":true,"username": "mak","userdomain": "newdomain.com","name": "mak peter"}
`
for single index:
`
POST socialdata/users/_bulk
{ "index": { "_index": "socialdata","_type": "users", "_id": 1 }}
{"status":true,"username": "mak","userdomain": "mydomain.com","name": "mak doe"}
`
elastic query :
it will return only two record
`
POST socialdata/users/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"username": "mak"
}
},
{
"match": {
"userdomain": "mydomain.com"
}
}
]
}
}
}
`
it will return only one record
`
POST socialdata/users/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"username": "mak"
}
},
{
"match": {
"userdomain": "newdomain.com"
}
}
]
}
}
}
`