Mongodb update operation inside sub array - javascript

I am extremely new to mongodb and am facing a little trouble with an update operation. Here is the document:
{
"username" : "amitverma",
"notifications" : {
"notification_add_friend" : [
{
"sender" : "macbook",
"action" : "",
"type" : "",
"objectType" : "request",
"objectUrl" : "",
"isUnread" : true
},
{
"sender" : "safari",
"action" : "",
"type" : "",
"objectType" : "request",
"objectUrl" : "",
"isUnread" : true
},
{
"sender" : "chrome",
"action" : "",
"type" : "",
"objectType" : "request",
"objectUrl" : "",
"isUnread" : true
}
]
},
"_id" : ObjectId("526598c86f45240000000001")
}
{
"username" : "macbook",
"notifications" : {
"notification_add_friend" : [
{
"sender" : "amitverma",
"action" : "",
"type" : "",
"objectType" : "a_r",
"objectUrl" : "",
"isUnread" : true
}
]
},
"_id" : ObjectId("526598d06f45240000000002")
}
I want to remove the sub array with {"sender":"safari"} within "username":"amitverma"
I have tried $elemMatch with $set, but just couldn't get the query correctly.

You don't want to use $set here, but $pull (see docs), and while you could use $elemMatch to further specify your query, you do not need to.
The following would pull all add friend notifications with {"sender": "safari"} from the sub array of documents matching {"username": "amitverma"}
db.yourcollection.update({"username": "amitverma"}, {
$pull: {"notifications.notifications_add_friend": {"sender": "safari"}}
})
As to your comment, if you wanted to update a particular element you would use $set in combination with $elemMatch and the positional operator $. For your example, something like:
db.yourcollection.update({
"username": "amitverma",
"notifications.notifications_add_friend": {
$elemMatch: {"sender": "safari"}
}
}, {
$set: {
"notifications.notifications_add_friend.$.isUnread": false
}
})

Related

getBypage in Nested Array in MongoDB using Aggregate

I am using mongoDB as backend server, I have nested array(one level array) like this
{
"_id" : ObjectId("60b1fc6d3c43f74e0c1dba92"),
"seriesId" : "60acebf73acb5b3a98d14331",
"name" : "Season 1",
"logoURL" : "uploads/season/1622277216401.png",
"yearOfPublish" : "2021-05-29",
"description" : "Season 1",
"createdBy" : ObjectId("609cbf49ba46cc3924859ab5"),
"createdOn" : "2021-05-29T08:33:49.480Z",
"episode" : [
{
"seasonId" : "60b1fc6d3c43f74e0c1dba92",
"name" : "Episode 1",
"id" : 0,
"logoURL" : "uploads/episode/1622278616899.png",
"dateOfTelecast" : null,
"description" : "sadfgh",
"duration" : "30",
"videoType" : "customURL",
"embedCode" : "",
"url" : "https://youtu.be/kbpsXMUr7ss",
"liveboxChannel" : "",
"createdOn" : "2021-05-29T08:56:59.230Z",
"createdBy" : ObjectId("609cbf49ba46cc3924859ab5"),
"_id" : "ZaVrpOLO5"
},
{
"seasonId" : "60b1fc6d3c43f74e0c1dba92",
"name" : "Episode 2",
"id" : 0,
"logoURL" : "uploads/episode/1622279206607.png",
"dateOfTelecast" : null,
"description" : "adfd",
"duration" : "30",
"videoType" : "customURL",
"embedCode" : "",
"url" : "https://youtu.be/kbpsXMUr7ss",
"liveboxChannel" : "",
"createdOn" : "2021-05-29T09:06:48.637Z",
"createdBy" : ObjectId("609cbf49ba46cc3924859ab5"),
"_id" : "9GKqXhxcH"
},}
I have more no of seasons. from the season collection,i have episode array under the name of Episode.
Now My frontend page required that episode array alone.
response = {episode: all the episode data} and this episode data is based on skip and limit value
I have tried something in mongodb,
db.getCollection('season_copy').aggregate([
{$project: {
episodes: {
$cond:{ if: { $isArray: "$episode" }, then: { input:"$episode" }, else: 0 }
},
},
},
])
Can anyone suggest me some idea?
Check this out:
Without aggregate:
db.getCollection('season_copy')
.find({ _id: ObjectID(id)})
.project({ episode: 1 }).toArray();
With aggregate:
MongoDB playground
db.getCollection('season_copy')
.aggregate([
{
$match: {
_id: ObjectId("60b1fc6d3c43f74e0c1dba92")
}
},
{
$project: {
episode: 1
}
}
])

How to filter out text fields in a complex query?

I've got a lot of doc filters on my UI (date ranges, checkboxes, input fields), so the query is generated dynamically - that's why I decided to create a boolean query, and push everything to must array. This is the example of my request:
const {
body: {
hits
}
} = await esclient.search({
from: filterQuery.page || 0,
size: filterQuery.limit || 1000,
index,
body: query
});
Checkboxes (I used additional bool.should inside must array) and date range work perfectly, but term/match filtering is not working at all:
{
"query": {
"bool": {
"must": [
{"match": { "issueNumber": "TEST-10" }}
]
}
}
}
The query above gives me all the documents from the index that contains "TEST" (with their scores), if I change match to term - it returns an empty array.
As my field is of a type 'text', I've also tried filter query - ES still gives all the documents with 'TEST' word:
{
"query": {
"bool": {
"must": [
{
"bool": {
"filter": {
"match": {"issueNumber": "TEST-10"}
}
}
}
]
}
}
}
This is how my hit looks like:
{
"_index" : "test_elastic",
"_type" : "_doc",
"_id" : "bj213hj2gghg213",
"_score" : 0.0,
"_source" : {
"date" : "2019-11-26T13:27:01.586Z",
"country" : "US",
"issueNumber" : "TEST-10",
}
Can someone give me input on how to filter the docs properly in complex query?
This is the structure of my index:
{
"test_elasticsearch" : {
"aliases" : { },
"mappings" : {
"properties" : {
"country" : {
"type" : "text"
},
"date" : {
"type" : "date"
},
"issueNumber" : {
"type" : "text"
}
}
},
"settings" : {
"index" : {
"creation_date" : "1574759226800",
"number_of_shards" : "1",
"number_of_replicas" : "1",
"uuid" : "PTDsdadasd-ERERER",
"version" : {
"created" : "7040299"
},
"provided_name" : "logs"
}
}
}
}
Ok, the problem is that your issueNumber field has not the right type, it should be keyword instead of text if your goal is to make exact searches on it. Same for country. Modify your mapping like this:
"properties" : {
"country" : {
"type" : "keyword"
},
"date" : {
"type" : "date"
},
"issueNumber" : {
"type" : "keyword"
}
}
Then reindex your data and your queries will work.

How to remove document in two different collection using same id at same time in mongodb on feathers application

I'm trying to remove document in two different collection using same id at same time. Is there any possibilities?
user collection:
{
"_id" : ObjectId("5a310315f685dd5038fecaaa"),
"userId" : 3,
"accountId" : 1,
"userType" : "DRIVER",
"firstName" : "Karthi",
"lastName" : "keyan",
"email" : "karthikeyan.a1#gmail.com",
"password" : "$2a$12$KFYc6riMnqTuzXhR0ssKZQmejAU4RF8FthAIQD4sgOUcALesp7DaJxK",
"phone" : "xyz",
"updatedAt" : ISODate("2017-12-13T10:38:13.492Z"),
"createdAt" : ISODate("2017-12-13T10:38:13.492Z"),
"__v" : 0
}
worker collection:
{
"_id" : ObjectId("5a310315f685dd5038fecaab"),
"workerId" : 1,
"accountId" : 1,
"name" : "Karthikeyan",
"email" : "karthikeyan.a1#gmail.com",
"mobile" : "xyz",
"type" : "DRIVER",
"joinDate" : ISODate("2017-12-13T10:38:13.070Z"),
"assignedVehicleId" : "23423231",
"licenseNumber" : "TN2506",
"createdBy" : "1",
"createdDate" : ISODate("2017-12-13T10:38:13.070Z"),
"updatedBy" : "1",
"updatedDate" : ISODate("2017-12-13T10:38:13.070Z"),
"regularHours" : 3600,
"regularRates" : 1500,
"overtimeRates" : 400,
"distanceRate" : 1000,
"stopRate" : 50,
"workerStatus" : "AVAILABLE",
"userId" : 3,
"__v" : 0
}
now i want to remove these two document at same time using userId.
Database adapters allow to call remove with null and a query that will remove all entries matching that query (see the documentation). In your case:
app.service('users').remove(null, { query: { userId: 3 } });
app.service('workers').remove(null, { query: { userId: 3 } });
Removing related entries (e.g. remove all workers for that user once the user has been removed) can be done in an after hook:
app.service('users').hooks({
after: {
async remove(context) {
const user = context.result;
await context.app.service('workers').remove(null, {
query: { userId: user.userId }
});
}
}
});

How to parse this datasnapshot using Firebase and JavaScript?

I have this data structure
{
"job-requests" : {
"pending" : {
"-KkyZGfqmiIVryyLAZpD" : {
"job_details" : "asd",
"job_type" : "Repair Required",
"location" : "123",
"location_lat" : 14.164633210106128,
"location_lng" : 121.24110514763743,
"timestamp" : 1495698316411
}
}
},
"office-info" : {
"123" : {
"office_acronym" : "123",
"office_contact_number" : "123-1234",
"office_current_head" : "None",
"office_name" : "123",
"office_parent_unit" : "123"
}
},
"office-location-list" : {
"123" : {
"location_lat" : 14.164633210106128,
"location_lng" : 121.24110514763743
}
},
"users" : {
"MBR5o37xafUyuLw14Xqa1ku0Zui1" : {
"designation" : "staff",
"email" : "123#asd.com",
"given_name" : "23",
"last_name" : "123",
"password" : "1234567",
"timestamp" : 1495617328793
},
"Nwacy3ADczgLC85OvSAgUNEGMkx2" : {
"designation" : "staff",
"email" : "adsasd#asdas.com",
"given_name" : "122123",
"last_name" : "12",
"password" : "asdasdsadasd",
"timestamp" : 1495681430048
}
}
}
I will be needing the keys [pending, active, finished] along with the data of the newly added child. This is how I accessed Firebase
firebase.database ().ref ('job-requests').on ('child_added', (snapshot) => {
console.log (snapshot.key); // prints out [pending, active, finished]
console.log (snapshot.val()); // prints out an object
});
It prints this on the console:
I tried using JSON.parse (), snapshot.child (path), snapshot.field, and snapshot[field] but errors are thrown out. How do I do this?
Your code gets all job requests. Since those are in a hierarchy by their state, your code will need to handle this:
firebase.database ().ref ('job-requests').on ('child_added', (snapshot) => {
snapshot.forEach((stateSnapshot) => {
console.log(stateSnapshot.key); // 'pending', etc
stateSnapshot.forEach((jobSnapshot) => {
console.log(jobSnapshot.key);
console.log(jobSnapshot.val());
});
});
});

How do I query referenced objects in MongoDB?

I've got two collections in my Mongo database, and the Foos contain references to one or more Bars:
Foo: {
prop1: true,
prop2: true,
bars: [
{
"$ref": "Bar",
"$id": ObjectId("blahblahblah")
}
]
}
Bar: {
testprop: true
}
What I want is to find all of the Foos that have at least one Bar that has its testprop set to true. I've tried this command, but it doesn't return any results:
db.Foo.find({ "bars.testprop" : { "$in": [ true ] } })
Any ideas?
You can now do it in Mongo 3.2 using $lookup
$lookup takes four arguments
from: Specifies the collection in the same database to perform the join with. The from collection cannot be sharded.
localField: Specifies the field from the documents input to the $lookup stage. $lookup performs an equality match on the localField to the foreignField from the documents of the from collection.
foreignField: Specifies the field from the documents in the from collection.
as: Specifies the name of the new array field to add to the input documents. The new array field contains the matching documents from the from collection.
db.Foo.aggregate(
{$unwind: "$bars"},
{$lookup: {
from:"bar",
localField: "bars",
foreignField: "_id",
as: "bar"
}},
{$match: {
"bar.testprop": true
}}
)
You can't. See http://www.mongodb.org/display/DOCS/Database+References
You have to do it in the client.
We have had a similar issue as we use MongoDB (3.4.4, actually 3.5.5 for testing) in combination with Morphia where we use #Referenece on a couple of entities. We are though not that happy with this solution and are considering removing these declarations and instead do the reference lookups manually.
I.e. we have a company collection and a user collection. The user entity in Morphia contains a #Refrence declaration on a company entity. The respective company collections contains entries like:
/* 1 */
{
"_id" : ObjectId("59a92501df01110fbb6a5dee"),
"name" : "Test",
"gln" : "1234567890123",
"uuid" : "f1f86961-e8d5-40bb-9d3f-fdbcf549066e",
"creationDate" : ISODate("2017-09-01T09:14:41.551Z"),
"lastChange" : ISODate("2017-09-01T09:14:41.551Z"),
"version" : NumberLong(1),
"disabled" : false
}
/* 2 */
{
"_id" : ObjectId("59a92501df01110fbb6a5def"),
"name" : "Sample",
"gln" : "3210987654321",
"uuid" : "fee69ee4-b29c-483b-b40d-e702b50b0451",
"creationDate" : ISODate("2017-09-01T09:14:41.562Z"),
"lastChange" : ISODate("2017-09-01T09:14:41.562Z"),
"version" : NumberLong(1),
"disabled" : false
}
while the user collections contains the following entries:
/* 1 */
{
"_id" : ObjectId("59a92501df01110fbb6a5df0"),
"userId" : "admin",
"userKeyEncrypted" : {
"salt" : "78e0528db239fd86",
"encryptedAttribute" : "e4543ddac7cca9757721379e4e70567bb13956694f473b73f7723ac2e2fc5245"
},
"passwordHash" : "$2a$10$STRNORu9rcbq4qYUMld4G.HJk8QQQQBmAswSNC/4PBn2bih0BvjM6",
"roles" : [
"ADMIN"
],
"company" : {
"$ref" : "company",
"$id" : ObjectId("59a92501df01110fbb6a5dee")
},
"uuid" : "b8aafdcf-d5c4-4040-a96d-8ab1a8608af8",
"creationDate" : ISODate("2017-09-01T09:14:41.673Z"),
"lastChange" : ISODate("2017-09-01T09:14:41.765Z"),
"version" : NumberLong(1),
"disabled" : false
}
/* 2 */
{
"_id" : ObjectId("59a92501df01110fbb6a5df1"),
"userId" : "sample",
"userKeyEncrypted" : {
"salt" : "e3ac48695dea5f51",
"encryptedAttribute" : "e804758b0fd13c219c3fc383eaa9267b70f7b8a1ed74f05575add713ce11804a"
},
"passwordHash" : "$2a$10$Gt2dq1vy4J9MeqDnXjokAOtvFcvbhe/g9wAENXFPaPxLAw1L4EULG",
"roles" : [
"USER"
],
"company" : {
"$ref" : "company",
"$id" : ObjectId("59a92501df01110fbb6a5def")
},
"uuid" : "55b62d4c-e5ee-408d-80c0-b79e02085b02",
"creationDate" : ISODate("2017-09-01T09:14:41.873Z"),
"lastChange" : ISODate("2017-09-01T09:14:41.878Z"),
"version" : NumberLong(1),
"disabled" : false
}
/* 3 */
{
"_id" : ObjectId("59a92501df01110fbb6a5df2"),
"userId" : "user",
"userKeyEncrypted" : {
"salt" : "ab9df671340a7d8b",
"encryptedAttribute" : "7d8ad4ca6ad88686d810c70498407032f1df830596f72d931880483874d9cce3"
},
"passwordHash" : "$2a$10$0FLFw3ixW79JIBrD82Ly6ebOwnEDliS.e7GmrNkFp2nkWDA9OE/RC",
"uuid" : "d02aef94-fc3c-4539-a22e-e43b8cd78aaf",
"creationDate" : ISODate("2017-09-01T09:14:41.991Z"),
"lastChange" : ISODate("2017-09-01T09:14:41.995Z"),
"version" : NumberLong(1),
"disabled" : false
}
In order to create a special company user view we also wanted to dereference the company in the user and only include selected fields. Based on a comment within a bug report we learned that MongoDB provides a $objectToArray: "$$ROOT.element" operation which basically splits fields of the given elements into key and value pairs. Note that $objectToArray operation was added in MongoDB version 3.4.4!
An aggregation on the company element contained in the user collection using the $objectToArray operation may look like below:
dp.user.aggregate([{
$project: {
"userId": 1,
"userKeyEncrypted": 1,
"uuid":1,
"roles": 1,
"passwordHash": 1,
"disabled": 1,
company: { $objectToArray: "$$ROOT.company" }
}
}])
The result of above aggregation looks like this:
/* 1 */
{
"_id" : ObjectId("59a92501df01110fbb6a5df0"),
"userId" : "admin",
"userKeyEncrypted" : {
"salt" : "78e0528db239fd86",
"encryptedAttribute" : "e4543ddac7cca9757721379e4e70567bb13956694f473b73f7723ac2e2fc5245"
},
"passwordHash" : "$2a$10$STRNORu9rcbq4qYUMld4G.HJk8QQQQBmAswSNC/4PBn2bih0BvjM6",
"roles" : [
"ADMIN"
],
"uuid" : "b8aafdcf-d5c4-4040-a96d-8ab1a8608af8",
"disabled" : false,
"company" : [
{
"k" : "$ref",
"v" : "company"
},
{
"k" : "$id",
"v" : ObjectId("59a92501df01110fbb6a5dee")
}
]
}
/* 2 */
{
"_id" : ObjectId("59a92501df01110fbb6a5df1"),
"userId" : "sample",
"userKeyEncrypted" : {
"salt" : "e3ac48695dea5f51",
"encryptedAttribute" : "e804758b0fd13c219c3fc383eaa9267b70f7b8a1ed74f05575add713ce11804a"
},
"passwordHash" : "$2a$10$Gt2dq1vy4J9MeqDnXjokAOtvFcvbhe/g9wAENXFPaPxLAw1L4EULG",
"roles" : [
"USER"
],
"uuid" : "55b62d4c-e5ee-408d-80c0-b79e02085b02",
"disabled" : false,
"company" : [
{
"k" : "$ref",
"v" : "company"
},
{
"k" : "$id",
"v" : ObjectId("59a92501df01110fbb6a5def")
}
]
}
/* 3 */
{
"_id" : ObjectId("59a92501df01110fbb6a5df2"),
"userId" : "user",
"userKeyEncrypted" : {
"salt" : "ab9df671340a7d8b",
"encryptedAttribute" : "7d8ad4ca6ad88686d810c70498407032f1df830596f72d931880483874d9cce3"
},
"passwordHash" : "$2a$10$0FLFw3ixW79JIBrD82Ly6ebOwnEDliS.e7GmrNkFp2nkWDA9OE/RC",
"uuid" : "d02aef94-fc3c-4539-a22e-e43b8cd78aaf",
"disabled" : false,
"company" : null
}
Now it's simply a matter of filtering unwanted stuff (i.e. users that have no company assigned and selecting the right array entries) in order to feed the $lookup operation #sidgate has already explained and copy the value of the dereferenced company into the user response.
I.e. an aggregation like the one below will perform an join and add the data of the company to users that have a company assigned as the as value defined in the lookup:
db.user.aggregate([
{ $project: { "userId": 1, "userKeyEncrypted": 1, "uuid":1, "roles": 1, "passwordHash": 1, "disabled": 1, company: { $objectToArray: "$$ROOT.company" }} },
{ $unwind: "$company" },
{ $match: { "company.k": "$id"} },
{ $lookup: { from: "company", localField: "company.v", foreignField: "_id", as: "company_data" } }
])
The result to the above aggregation can be seen below:
/* 1 */
{
"_id" : ObjectId("59a92501df01110fbb6a5df0"),
"userId" : "admin",
"userKeyEncrypted" : {
"salt" : "78e0528db239fd86",
"encryptedAttribute" : "e4543ddac7cca9757721379e4e70567bb13956694f473b73f7723ac2e2fc5245"
},
"passwordHash" : "$2a$10$STRNORu9rcbq4qYUMld4G.HJk8QQQQBmAswSNC/4PBn2bih0BvjM6",
"roles" : [
"ADMIN"
],
"uuid" : "b8aafdcf-d5c4-4040-a96d-8ab1a8608af8",
"disabled" : false,
"company" : {
"k" : "$id",
"v" : ObjectId("59a92501df01110fbb6a5dee")
},
"company_data" : [
{
"_id" : ObjectId("59a92501df01110fbb6a5dee"),
"name" : "Test",
"gln" : "1234567890123",
"uuid" : "f1f86961-e8d5-40bb-9d3f-fdbcf549066e",
"creationDate" : ISODate("2017-09-01T09:14:41.551Z"),
"lastChange" : ISODate("2017-09-01T09:14:41.551Z"),
"version" : NumberLong(1),
"disabled" : false
}
]
}
/* 2 */
{
"_id" : ObjectId("59a92501df01110fbb6a5df1"),
"userId" : "sample",
"userKeyEncrypted" : {
"salt" : "e3ac48695dea5f51",
"encryptedAttribute" : "e804758b0fd13c219c3fc383eaa9267b70f7b8a1ed74f05575add713ce11804a"
},
"passwordHash" : "$2a$10$Gt2dq1vy4J9MeqDnXjokAOtvFcvbhe/g9wAENXFPaPxLAw1L4EULG",
"roles" : [
"USER"
],
"uuid" : "55b62d4c-e5ee-408d-80c0-b79e02085b02",
"disabled" : false,
"company" : {
"k" : "$id",
"v" : ObjectId("59a92501df01110fbb6a5def")
},
"company_data" : [
{
"_id" : ObjectId("59a92501df01110fbb6a5def"),
"name" : "Sample",
"gln" : "3210987654321",
"uuid" : "fee69ee4-b29c-483b-b40d-e702b50b0451",
"creationDate" : ISODate("2017-09-01T09:14:41.562Z"),
"lastChange" : ISODate("2017-09-01T09:14:41.562Z"),
"version" : NumberLong(1),
"disabled" : false
}
]
}
As can hopefully be seen we only have the two users that contained a company reference and the two users now have also the complete company data in the response. Now additional filtering can be applied to get rid of the key/value helper and also to hide unwanted data.
The final query we came up with looks like this:
db.user.aggregate([
{ $project: { "userId": 1, "userKeyEncrypted": 1, "uuid":1, "roles": 1, "passwordHash": 1, "disabled": 1, company: { $objectToArray: "$$ROOT.company" }} },
{ $unwind: "$company" },
{ $match: { "company.k": "$id"} },
{ $lookup: { from: "company", localField: "company.v", foreignField: "_id", as: "company_data" } },
{ $project: { "userId": 1, "userKeyEncrypted": 1, "uuid":1, "roles": 1, "passwordHash": 1, "disabled": 1, "companyUuid": { $arrayElemAt: [ "$company_data.uuid", 0 ] } } }
])
Which finally returns our desired representation:
/* 1 */
{
"_id" : ObjectId("59a92501df01110fbb6a5df0"),
"userId" : "admin",
"userKeyEncrypted" : {
"salt" : "78e0528db239fd86",
"encryptedAttribute" : "e4543ddac7cca9757721379e4e70567bb13956694f473b73f7723ac2e2fc5245"
},
"passwordHash" : "$2a$10$STRNORu9rcbq4qYUMld4G.HJk8QQQQBmAswSNC/4PBn2bih0BvjM6",
"roles" : [
"ADMIN"
],
"uuid" : "b8aafdcf-d5c4-4040-a96d-8ab1a8608af8",
"disabled" : false,
"companyUuid" : "f1f86961-e8d5-40bb-9d3f-fdbcf549066e"
}
/* 2 */
{
"_id" : ObjectId("59a92501df01110fbb6a5df1"),
"userId" : "sample",
"userKeyEncrypted" : {
"salt" : "e3ac48695dea5f51",
"encryptedAttribute" : "e804758b0fd13c219c3fc383eaa9267b70f7b8a1ed74f05575add713ce11804a"
},
"passwordHash" : "$2a$10$Gt2dq1vy4J9MeqDnXjokAOtvFcvbhe/g9wAENXFPaPxLAw1L4EULG",
"roles" : [
"USER"
],
"uuid" : "55b62d4c-e5ee-408d-80c0-b79e02085b02",
"disabled" : false,
"companyUuid" : "fee69ee4-b29c-483b-b40d-e702b50b0451"
}
Some final note to this approach: This aggregation isn't very fast, sadly, but at least it gets the job done. I haven't tested it with an array of references as originally asked though this may require some additional unwindings probably.
Update: A further way of aggregating the data, which is more in line with the comments in the above mentioned bug report, can be seen below:
db.user.aggregate([
{ $project: { "userId": 1, "userKeyEncrypted": 1, "uuid":1, "roles": 1, "passwordHash": 1, "disabled": 1, companyRefs: { $let: { vars: { refParts: { $objectToArray: "$$ROOT.company" }}, in: "$$refParts.v" } } } },
{ $match: { "companyRefs": { $exists: true } } },
{ $project: { "userId": 1, "userKeyEncrypted": 1, "uuid":1, "roles": 1, "passwordHash": 1, "disabled": 1, "companyRef": { $arrayElemAt: [ "$companyRefs", 1 ] } } },
{ $lookup: { from: "company", localField: "companyRef", foreignField: "_id", as: "company_data" } },
{ $project: { "userId": 1, "userKeyEncrypted": 1, "uuid":1, "roles": 1, "passwordHash": 1, "disabled": 1, "companyUuid": { $arrayElemAt: [ "$company_data.uuid", 0 ] } } }
])
Here the $let: { vars: ..., in: ... } operation copies the key and value of the reference into an own object and thus allows later on to lookup the reference via the corresponding operation.
Which of these aggregations performs better has yet to be profiled.
Well.. you could query the Bar Model for the _id of all documents with testprop: true, then do a find $in and populate bars on the Foo Model with an array of those _id's you got from the first query.. :P
Maybe that counts as "In the Client" :P just a thought.
It wasn't possible before, but improvements from Mongo v3.4 we can get very close to it.
You can do it with mongo-join-query. Your code would look like this:
const mongoose = require("mongoose");
const joinQuery = require("mongo-join-query");
joinQuery(
mongoose.models.Foo,
{
find: { "bars.testprop": { $in: [true] } },
populate: ["bars"]
},
(err, res) => (err ? console.log("Error:", err) : console.log("Success:", res.results))
);
How does it work?
Behind the scenes mongo-join-query will use your Mongoose schema to determine which models to join and will create an aggregation pipeline that will perform the join and the query.
Disclosure: I wrote this library to tackle precisely this use case.

Categories

Resources