Distinct list of values from embedded document in mongodb - mongodb

I'm going crazy... I come from the sql world an this is my first real experience with mongodb.
I have a given json/object structure (I know, this is not perfect but it has to be so because of existing data and other applications), stored in a mongodb (v3.4) with Restheart as the http frontend.
The documents look like this
{
"_id" : ObjectId("5855cbc9fc3baea81e937261"),
"_etag" : ObjectId("5855cbc99b971700050d8adc"),
"log" : [
"858489b087f7472dbb8d1012dee4cd5d.d",
NumberLong("12345678901234"),
{
"ext" : {
"text" : "someone did something at somewhere (some street 123) +38 USD",
"markup" : [
[
"user",
{
"plain" : "someone",
"team" : "master"
}
], [
"TEXT",
{
"plain" : " did something at "
}
], [
"location",
{
"name" : "somewhere",
"plain" : "some street 123",
"team" : "master"
}
], [
"TEXT",
{
"plain" : "38"
}
], [
"TEXT",
{
"plain" : "USD"
}
]
],
"category" : 1,
"team" : "master"
}
}
]
}
And I want to get a distinct list of the usern.plain names. Theoretically db.logs.distinct("log.2.ext.markup.0.1.plain") would do exactly what I need. But as far as I understand, there is no way to use db.distinct with Restheart. I tried this using views but it seems, I can not use db.distinct in views too.
This are my experiments...
{ "aggrs" : [
{ "stages" : [
{ "_$project" : { "user" : "$log.2.ext.markup.0.1.plain"}},
{ "_$unwind" : "$user"},
{ "_$unwind" : "$user"},
{ "_$unwind" : "$user"},
{ "_$unwind" : "$user"},
{ "_$unwind" : "$user"},
{ "_$unwind" : "$user"},
{ "_$group" : { "_id" : "$user"}}
],
"type" : "pipeline",
"uri" : "unique_users1"
},
{ "stages" : [
{ "_$match": { "log": { "_$exists": true, "_$ne": null }}},
{ "_$unwind" : "$log"},
{ "_$unwind" : "$log.2"},
{ "_$unwind" : "$log.2.ext"},
{ "_$unwind" : "$log.2.ext.markup"},
{ "_$unwind" : "$log.2.ext.markup.0"},
{ "_$unwind" : "$log.2.ext.markup.0.1"},
{ "_$group" : { "_id" : "$log.2.ext.markup.0.1.plain"}}
],
"type" : "pipeline",
"uri" : "unique_users2"
},
{ "stages" : [
{ "_$match" : {"log" : { "_$exists" : true }}},
{ "_$replaceRoot" : { "newRoot" : { "user": "$log.2.ext.markup.0.1.plain"}}}
],
"type" : "pipeline",
"uri" : "unique_users3"
},
{ "stages" : [
{ "_$group" : { "_id" : 1 , "users" : { "_$addToSet" : "$log.2.ext.markup.0.1.plain"}}}
],
"type" : "pipeline",
"uri" : "unique_users4"
}
]}
But results are... nothing or nearly nothing
{
"_embedded": {
"rh:result": [
{
"_id": 1,
"users": [
[]
]
}
]
},
"_returned": 1,
"_size": 1,
"_total_pages": 1
}

Related

ElasticSearch filter on array along with multiple match queries

I am trying to filter the documents based on some tags and subcategory.
Some documents:
[{
"_id" : "2oukjh8o9qy2ejhasdkqwe",
"productName" : "ASSORTED DOUGHNUT 1PC",
"productSubCategory" : [
{
"label" : "Veg",
"imageUrl" : "/catImg/fandA.svg"
}
],
"isVisible" : true,
"tags" : [
{
"tagImageUrl" : " ",
"label" : "Favorites",
"tag" : "favorites"
}
]
},
{
"_id" : "638daf9f42e6efc7f06641c2",
"isVisible" : true,
"productName" : "FILTER COFFEE",
"productSubCategory" : [
{
"_id" : ObjectId("638daf18ed445826c06a7328"),
"label" : "Veg"
}
],
"tags" : [
{
"tagImageUrl" : " ",
"label" : "Trending",
"tag" : "trending"
},
{
"tagImageUrl" : " ",
"label" : "Favorites",
"tag" : "favorites"
},
{
"tagImageUrl" : " ",
"label" : "Cabin Friendly",
"tag" : "cabinfriendly"
}
]
},
{
"_id" : "6389d7f942e6efc7f05d51e0",
"isVisible" : true,
"productName" : "ILLY DOPPIO",
"productSubCategory" : [
{
"_id" : ObjectId("638d97236612ca5d5ceb53b9"),
"label" : "Non-Veg"
}
],
"tags" : [
{
"tagImageUrl" : " ",
"label" : "Cabin Friendly",
"tag" : "cabinfriendly"
}
]
}]
Query I am trying
{
"query": {
"bool": {
"must": [
{
"match": {
"productSubCategory.label": {
"query": "Veg",
"operator": "and"
}
}
},
{
"match": {
"isVisible": true
}
}
],
"filter": {
"terms": {
"tags.tag": [
"favorites",
"cabinfriendly"
]
}
}
}
}
}
Requirement
The result documents must have any of the tags.tag provided in the query. Must have isVisible as true and productSubCategory.label as provided in the query.
With the above query I am getting Non-Veg items as well.
Because you are using match query which will do the free text search and it will match with the non-veg as well. You can use term query with keyword type insted of match query like shown below:
{
"query": {
"bool": {
"must": [
{
"term": {
"productSubCategory.label.keyword": {
"value": "Veg"
}
}
},
{
"match": {
"isVisible": true
}
}
],
"filter": {
"terms": {
"tags.tag": [
"favorites",
"cabinfriendly"
]
}
}
}
}
}
Please note that i have replace field name productSubCategory.label with productSubCategory.label.keyword

MongoDB join two collections with between clause

There is a collection "Printers":
{
"_id" : ObjectId("5cc02f9b9931de72296ba6c2"),
"model" : "Xerox WorkCentre 3315",
"serial" : "3255498494",
"date" : ISODate("2019-04-25T08:57:48.001+0000"),
"pages" : NumberInt(4868),
"location" : "New location",
"ip" : "10.159.0.35",
"ip_int" : NumberInt(178192419)
}
and "Branches" collection:
{
"_id" : ObjectId("5cb4799b8c0cfe35e4a4c266"),
"name" : "Office 1",
"ip_start" : NumberLong(178192384),
"ip_end" : NumberLong(178194431)
}
// ----------------------------------------------
{
"_id" : ObjectId("5cb479e68c0cfe35e4a4c269"),
"name" : "Office 2",
"ip_start" : NumberLong(3232258048),
"ip_end" : NumberLong(3232258303)
}
"Branches" collection contains ip addresses converted into integer value, i.e. 192.168.0.1 is 3232235521. Each record in Branches describes subnet.
Each printer located in one branch.
If printers.ip_int between branches record [ip_start;ip_end] then query should return all fields from Printer and one field "Name" from "Branches" collection.
How can i do this?
You need a lookup with custom pipeline where you can specify "between" condition:
db.Branches.aggregate([
{
$lookup: {
from: "Printers",
let: { ip_start: "$ip_start", ip_end: "$ip_end" },
pipeline: [
{
$match: {
$expr: {
$and: [
{ "$gte": [ "$ip_int", "$$ip_start" ] },
{ "$lte": [ "$ip_int", "$$ip_end" ] },
]
}
}
}
],
as: "Printers"
}
}
])
db.getCollection("printers").aggregate(
[
{
"$lookup" : {
"from" : "branches",
"let" : {
"ip_int" : "$ip_int"
},
"pipeline" : [
{
"$match" : {
"$expr" : {
"$and" : [{"$gte" : ["$$ip_int", "$ip_start"]},
{ "$lte" : ["$$ip_int", "$ip_end"]}
]
}
}
}
], "as" : "Printers"
}
},
{
"$sort" : {
"ip_int" : 1.0
}
},
{
"$unwind" : {
"path" : "$Printers"
}
},
{
"$addFields" : {
"filial" : "$Printers.name"
}
},
{
"$project" : {
"Printers" : false, "ip_int" : false
}
}
]);

Return specific array value field in aggregate

I have a issue in MongoDB i'm trying to build a very complex aggregate query, and its work almost as i want it, but i still have trobles, and the problems is i need to move a spefiect field so i can use it later.
My aggregate look like this right now.
db.getCollection('travel_sights').aggregate([{
'$match': {
'preview.photo' : {
'$exists':true
},
'_id': {
'$in' : [ObjectId("5b7af9701fbad410e10f32f7")]
}
}
},{
'$unwind' : '$preview.photo'
}, {
'$lookup':{
'from' : 'media_data',
'localField' : '_id',
'foreignField':'bind',
'as':'media'
}
}])
and it will return data like this.
{
"_id" : ObjectId("5b7af9701fbad410e10f32f7"),
"preview" : {
"photo" : {
"id" : ObjectId("5b7affea1fbad441494a663b"),
"sort" : 0
}
},
"media" : [
{
"_id" : ObjectId("5b7affea1fbad441494a663b")
},
{
"_id" : ObjectId("5b7b002d1fbad441494a663c")
},
{
"_id" : ObjectId("5b7b00351fbad441494a663d")
},
{
"_id" : ObjectId("5b7d9baa1fbad410de638bbb")
},
{
"_id" : ObjectId("5b7d9bae1fbad410e10f32f9")
},
{
"_id" : ObjectId("5b7d9bb11fbad441494a663e")
},
{
"_id" : ObjectId("5b7d9bb41fbad4ff97273402")
},
{
"_id" : ObjectId("5b7d9bb71fbad4ff99527e82")
},
{
"_id" : ObjectId("5b7d9bbb1fbad410de638bbc")
},
{
"_id" : ObjectId("5b7d9bbe1fbad410e10f32fa")
},
{
"_id" : ObjectId("5b7d9bc11fbad441494a663f")
},
{
"_id" : ObjectId("5b7d9bc41fbad4ff97273403")
},
{
"_id" : ObjectId("5b7d9bc71fbad4ff99527e83")
},
{
"_id" : ObjectId("5b7d9bca1fbad410de638bbd")
},
{
"_id" : ObjectId("5b7d9bcd1fbad441494a6640")
},
{
"_id" : ObjectId("5b7d9bd01fbad4ff97273404")
}
]
}
{
"_id" : ObjectId("5b7af9701fbad410e10f32f7"),
"preview" : {
"photo" : {
"id" : ObjectId("5b7b002d1fbad441494a663c"),
"sort" : 0
}
},
"media" : [
{
"_id" : ObjectId("5b7affea1fbad441494a663b")
},
{
"_id" : ObjectId("5b7b002d1fbad441494a663c")
},
{
"_id" : ObjectId("5b7b00351fbad441494a663d")
},
{
"_id" : ObjectId("5b7d9baa1fbad410de638bbb")
},
{
"_id" : ObjectId("5b7d9bae1fbad410e10f32f9")
},
{
"_id" : ObjectId("5b7d9bb11fbad441494a663e")
},
{
"_id" : ObjectId("5b7d9bb41fbad4ff97273402")
},
{
"_id" : ObjectId("5b7d9bb71fbad4ff99527e82")
},
{
"_id" : ObjectId("5b7d9bbb1fbad410de638bbc")
},
{
"_id" : ObjectId("5b7d9bbe1fbad410e10f32fa")
},
{
"_id" : ObjectId("5b7d9bc11fbad441494a663f")
},
{
"_id" : ObjectId("5b7d9bc41fbad4ff97273403")
},
{
"_id" : ObjectId("5b7d9bc71fbad4ff99527e83")
},
{
"_id" : ObjectId("5b7d9bca1fbad410de638bbd")
},
{
"_id" : ObjectId("5b7d9bcd1fbad441494a6640")
},
{
"_id" : ObjectId("5b7d9bd01fbad4ff97273404")
}
]
}
{
"_id" : ObjectId("5b7af9701fbad410e10f32f7"),
"preview" : {
"photo" : {
"id" : ObjectId("5b7b00351fbad441494a663d"),
"sort" : 0,
"primary" : false
}
},
"media" : [
{
"_id" : ObjectId("5b7affea1fbad441494a663b")
},
{
"_id" : ObjectId("5b7b002d1fbad441494a663c")
},
{
"_id" : ObjectId("5b7b00351fbad441494a663d")
},
{
"_id" : ObjectId("5b7d9baa1fbad410de638bbb")
},
{
"_id" : ObjectId("5b7d9bae1fbad410e10f32f9")
},
{
"_id" : ObjectId("5b7d9bb11fbad441494a663e")
},
{
"_id" : ObjectId("5b7d9bb41fbad4ff97273402")
},
{
"_id" : ObjectId("5b7d9bb71fbad4ff99527e82")
},
{
"_id" : ObjectId("5b7d9bbb1fbad410de638bbc")
},
{
"_id" : ObjectId("5b7d9bbe1fbad410e10f32fa")
},
{
"_id" : ObjectId("5b7d9bc11fbad441494a663f")
},
{
"_id" : ObjectId("5b7d9bc41fbad4ff97273403")
},
{
"_id" : ObjectId("5b7d9bc71fbad4ff99527e83")
},
{
"_id" : ObjectId("5b7d9bca1fbad410de638bbd")
},
{
"_id" : ObjectId("5b7d9bcd1fbad441494a6640")
},
{
"_id" : ObjectId("5b7d9bd01fbad4ff97273404")
}
]
}
and what you can se the last data have preview.photo.primary on it, and this field i want to return when i'm done with my aggregate query.
My final query look like this:
db.getCollection('travel_sights').aggregate([{
'$match': {
'preview.photo' : {
'$exists':true
},
'_id': {
'$in' : [ObjectId("5b7af9701fbad410e10f32f7")]
}
}
},{
'$unwind' : '$preview.photo'
}, {
'$lookup':{
'from' : 'media_data',
'localField' : '_id',
'foreignField':'bind',
'as':'media'
}
},{
'$unwind':'$media'
},{
'$project' : {
'preview' : 1,
'media': 1,
}
}, {
'$group': {
'_id':'$media._id',
'primary': {
'$first':'$preview'
}
}
}])
The problem here is when i want $preview return so i can find the primary about it, its allways only return the first where the value not exists, if i use $push the problem is i get every thing.
is there a way so i can pick the right primary value in my return? have trying $addFields to but whitout eny kind of lock.
Travel_sights data:
{
"_id" : ObjectId("5b7af9701fbad410e10f32f7"),
"city_id" : ObjectId("5b6d0cb6222d4c70b803eaeb"),
"activated" : true,
"deleted" : false,
"url" : "url is here",
"name" : "title of it here",
"updated_at" : ISODate("2018-08-22T17:22:27.000Z"),
"content" : "content here",
"preview" : {
"photo" : [
{
"id" : ObjectId("5b7affea1fbad441494a663b"),
"sort" : 0
},
{
"id" : ObjectId("5b7b002d1fbad441494a663c"),
"sort" : 0
},
{
"id" : ObjectId("5b7b00351fbad441494a663d"),
"sort" : 0,
"primary" : true
},
{
"id" : ObjectId("5b7d9baa1fbad410de638bbb"),
"sort" : 0
},
{
"id" : ObjectId("5b7d9bae1fbad410e10f32f9"),
"sort" : 0
},
{
"id" : ObjectId("5b7d9bb11fbad441494a663e"),
"sort" : 0
},
{
"id" : ObjectId("5b7d9bb41fbad4ff97273402"),
"sort" : 0,
"primary" : false
},
{
"id" : ObjectId("5b7d9bb71fbad4ff99527e82"),
"sort" : 0,
"primary" : false
},
{
"id" : ObjectId("5b7d9bbb1fbad410de638bbc"),
"sort" : 0
},
{
"id" : ObjectId("5b7d9bbe1fbad410e10f32fa"),
"sort" : 0
},
{
"id" : ObjectId("5b7d9bc11fbad441494a663f"),
"sort" : 0
},
{
"id" : ObjectId("5b7d9bc41fbad4ff97273403"),
"sort" : 0,
"primary" : false
},
{
"id" : ObjectId("5b7d9bc71fbad4ff99527e83"),
"sort" : 0,
"primary" : false
},
{
"id" : ObjectId("5b7d9bca1fbad410de638bbd"),
"sort" : 0,
"primary" : false
},
{
"id" : ObjectId("5b7d9bcd1fbad441494a6640"),
"sort" : 0,
"primary" : false
},
{
"id" : ObjectId("5b7d9bd01fbad4ff97273404"),
"sort" : 0
}
]
}
}
3 sample foto bind data here:
{
"_id" : ObjectId("5b7affea1fbad441494a663b"),
"file-name" : "55575110311__0F115282-B5A0-4654-AA44-B7DC2C682992.jpeg",
"options" : [
ObjectId("5b6fb855222d4c70b8041093")
],
"type" : "images",
"files" : [
{
"width" : 70,
"height" : 53
},
{
"width" : 400,
"height" : 300
},
{
"width" : 800,
"height" : 600
},
{
"width" : 1600,
"height" : 1200
}
],
"bind" : [
ObjectId("5b7af9701fbad410e10f32f7")
]
}
{
"_id" : ObjectId("5b7b002d1fbad441494a663c"),
"file-name" : "55575110748__E7B07EFD-9F7E-40D6-8B57-38F708E4C0C0.jpeg",
"options" : [
ObjectId("5b6fb855222d4c70b8041093")
],
"type" : "images",
"files" : [
{
"width" : 70,
"height" : 53
},
{
"width" : 400,
"height" : 300
},
{
"width" : 800,
"height" : 600
},
{
"width" : 1600,
"height" : 1200
}
],
"bind" : [
ObjectId("5b7af9701fbad410e10f32f7")
],
"description" : "this is secoudn demo!",
"title" : "demo 3"
}
{
"_id" : ObjectId("5b7b00351fbad441494a663d"),
"file-name" : "paris2.jpg",
"options" : [
ObjectId("5b6fb855222d4c70b8041093")
],
"type" : "images",
"files" : [
{
"width" : 70,
"height" : 53
},
{
"width" : 400,
"height" : 300
},
{
"width" : 800,
"height" : 600
},
{
"width" : 1600,
"height" : 1200
}
],
"bind" : [
ObjectId("5b7af9701fbad410e10f32f7")
],
"description" : "this is a demo1 :)",
"title" : "demo"
}
You can filter out the element from the array where the primary field exists using $filter aggregation and then easily $group with the media._id field and get the $first document value.
Finally your query will be
db.getCollection("travel_sights").aggregate([
{ "$match": {
"preview.photo" : { "$exists":true },
"_id": { "$in" : [ ObjectId("5b7af9701fbad410e10f32f7") ] }
}},
{ "$addFields": {
"preview.photo": {
"$arrayElemAt": [
{ "$filter": {
"input": "$preview.photo",
"as": "photo",
"cond": { "$ne": [ "$$photo.primary", undefined ] }
}}, 0
]
}
}},
{ "$lookup":{
"from" : "media_data",
"localField" : "_id",
"foreignField": "bind",
"as": "media"
}},
{ "$unwind":"$media" },
{ "$project" : { "preview" : 1, "media": 1, }},
{ "$group": {
"_id": "$media._id",
"primary": { "$first": "$preview" }
}}
])

Return intersection of subdocument array with user defined array?

I am trying to use Mongo Aggregation Framework to find out intersection between an array inside my document AND another user defined array.
I don't get a correct result and my guess is its because of the fact that I have array inside of an array.
Here is my data set.
My documents:
{
"_id" : 1,
"pendingEntries" : [
{
"entryID" : ObjectId("5701b4c3c6b126083332e65f"),
"tags" : [
{
"tagKey" : "owner",
"tagValue" : "john"
},
{
"tagKey" : "ErrorCode",
"tagValue" : "7001"
},
{
"tagKey" : "ErrorDescription",
"tagValue" : "error123"
}
],
"entryTime" : ISODate("2016-04-04T00:26:43.167Z")
}
]
},
/* 1 */
{
"_id" : 2,
"pendingEntries" : [
{
"entryID" : ObjectId("5701b4c3c6b126083332e65d"),
"tags" : [
{
"tagKey" : "owner",
"tagValue" : "peter"
},
{
"tagKey" : "ErrorCode",
"tagValue" : "6001"
},
{
"tagKey" : "JIRA",
"tagValue" : "Oabc-123"
}
],
"entryTime" : ISODate("2016-04-04T00:26:43.167Z")
}
]
},
/* 2 */
{
"_id" : 3,
"pendingEntries" : [
{
"entryID" : ObjectId("5701b4c3c6b126083332e65c"),
"tags" : [
{
"tagKey" : "owner",
"tagValue" : "abc"
},
{
"tagKey" : "ErrorCode",
"tagValue" : "6001"
},
{
"tagKey" : "JIRA",
"tagValue" : "abc-123"
}
],
"entryTime" : ISODate("2016-04-04T00:26:43.167Z")
}
]
}
My Query:
db.entrylike.aggregate(
[
{ $project: { "pendingEntries.entryID": 1, "common": { $setIntersection: [ "$pendingEntries.tags", [{ "tagKey" : "ErrorCode", "tagValue" : "7001" }] ] } } }
]
)
Result:
{
"result" : [
{
"_id" : 1,
"pendingEntries" : [
{
"entryID" : ObjectId("5701b4c3c6b126083332e65f")
}
],
"common" : []
},
{
"_id" : 2,
"pendingEntries" : [
{
"entryID" : ObjectId("5701b4c3c6b126083332e65d")
}
],
"common" : []
},
{
"_id" : 3,
"pendingEntries" : [
{
"entryID" : ObjectId("5701b4c3c6b126083332e65c")
}
],
"common" : []
}
],
"ok" : 1
}
I am not expecting first common field to be empty. Can someone let me know what is it that I am doing wrong? Or any work arounds that I can take.
I am using mongodb 3.0.8. I am aware of the fact that Mongodb 3.2 can offer some features which will fulfill my needs but 3.2 upgrade is not in our pipeline soon and I am looking to resolve this using Mongo3.0 if possible.
My goal is to either replace tags array with the common elements from the user defined list or add a new field with common elements. My am trying to to the later in my example.
The reason you the common field is empty is because your "pendingEntries" array and your user defined array have not element in common. What you really want is to return an array that contains the elements that appear in your "tags" array and your user defined array. To do that you can simply use the $map operator and apply the $setIntersection operator to each subdocument "tags" in the "pendingEntries" array.
db.entrylike.aggregate([
{ "$project": {
"common": {
"$map": {
"input": "$pendingEntries",
"as": "p",
"in": {
"entryID": "$$p.entryID",
"tags": {
"$setIntersection": [
"$$p.tags",
{ "$literal": [
{
"tagKey" : "ErrorCode",
"tagValue" : "7001"
}
]}
]
}
}
}
}
}}
])
Which returns:
{
"_id" : 1,
"common" : [
{
"entryID" : ObjectId("5701b4c3c6b126083332e65f"),
"tags" : [
{
"tagKey" : "ErrorCode",
"tagValue" : "7001"
}
]
}
]
}
{
"_id" : 2,
"common" : [
{
"entryID" : ObjectId("5701b4c3c6b126083332e65d"),
"tags" : [ ]
}
]
}
{
"_id" : 3,
"common" : [
{
"entryID" : ObjectId("5701b4c3c6b126083332e65c"),
"tags" : [ ]
}
]
}

Querying subdocument inside a subdocument of a collection in Mongodb

I have the collection named companies as below.
I want to query the url corresponding to C1S1category1 . I do not know which companyName it belongs and which catergories it belongs to.
Please can you let me know what query I need to use in Mongoshell to query the document having catergoryname as C1S1category1
{"companyName": "C1",
"url": "www.com1",
"categories" : [
{"SlNo" : 1,
"url" : "www.com1",
"subcategories" : [
{
"CatergoryName":"C1S1category1",
"Url" : "www.com3"
},
{
"CatergoryName":"C1S1category2",
"Url" : "www.com3"
}
]
},
{
"SlNo" : 2,
"url" : "www.com1",
"subcategories" : [
{
"CatergoryName":"C1S2category1",
"Url" : "www.com3"
},
{
"CatergoryName":"C1S2category2",
"Url" : "www.com3"
}
]
}
]
},
{"companyName": "C2",
"url": "www.com21",
"categories" : [
{"SlNo" : 1,
"url" : "www.com22",
"subcategories" : [
{
"CatergoryName":"C2S1category1",
"Url" : "www.com23"
},
{
"CatergoryName":"C2S1category2",
"Url" : "www.com23"
}
]
},
{
"SlNo" : 2,
"url" : "www.com1",
"subcategories" : [
{
"CatergoryName":"C2S2category1",
"Url" : "www.com23"
},
{
"CatergoryName":"C2S2category2",
"Url" : "www.com23"
}
]
}
]
}
You need to use $elemMatch to get required output as following:
db.collection.find({
"categories": {
$elemMatch: {
subcategories: {
$elemMatch: {
CatergoryName: "C1S1category1"
}
}
}
}
},{"categories.$":1,"companyName":1,"url":1}).pretty()