in mongo, cannot perform $setIntersection on array with aggregate into project - mongodb

I have this two collection which each document presents a chat session:
{
"_id" : ObjectId("58136ba83bdddd2d3cd4b3fb"),
"Created" : ISODate("2016-10-28T15:15:52.563Z"),
"Messages" : [
{
"Created" : ISODate("2016-10-28T15:15:52.567Z"),
"ReadBy" : [
ObjectId("57c96a14870ae36ede4d8085"),
ObjectId("57c972b6fc8effecde6cf0fa")
],
"Content" : "Hello"
}
]
}
{
"_id" : ObjectId("5813ac380a45415df8e7fc08"),
"Created" : ISODate("2016-10-28T15:16:52.563Z"),
"Messages" : [
{
"Created" : ISODate("2016-10-28T15:15:52.567Z"),
"ReadBy" : [
ObjectId("57c96a14870ae36ede4d8234"),
ObjectId("57c972b6fc8effecde6cf987")
],
"Content" : "Hello2"
}
]
}
I am trying to use $aggregate with $project, and to perform a simple $setIntersection in order to get matching ObjectIds.
This is the projection:
db.getCollection('Chats').aggregate([
{
$project: {
Created: 1,
Messages: 1,
Match: {
$setIntersection: [ "$Messages.ReadBy", [ObjectId("57c96a14870ae36ede4d8085")] ]
},
ReadBy: "$Messages.ReadBy"
}
}
])
The result i am getting from this aggregate, seems to insert "$Messages.ReadBy" into Sub-Array of Array [[ObjectId("....")]] for example.
The Result is that $setIntersection returns null although there is something relevant for me, and the new "ReadBy" field i added for debug shows the problem of sub-array:
{
"_id" : ObjectId("58136ba83bdddd2d3cd4b3fb"),
"Created" : ISODate("2016-10-28T15:15:52.563Z"),
"Messages" : [
{
"Created" : ISODate("2016-10-28T15:15:52.567Z"),
"ReadBy" : [
ObjectId("57c96a14870ae36ede4d8085"),
ObjectId("57c972b6fc8effecde6cf0fa")
],
"Content" : "Hello"
}
],
"Match" : [],
"ReadBy" : [
[
ObjectId("57c96a14870ae36ede4d8085"),
ObjectId("57c972b6fc8effecde6cf0fa")
]
]
}
{
"_id" : ObjectId("5813ac380a45415df8e7fc08"),
"Created" : ISODate("2016-10-28T15:16:52.563Z"),
"Messages" : [
{
"Created" : ISODate("2016-10-28T15:15:52.567Z"),
"ReadBy" : [
ObjectId("57c96a14870ae36ede4d8234"),
ObjectId("57c972b6fc8effecde6cf987")
],
"Content" : "Hello2"
}
],
"Match" : [],
"ReadBy" : [
[
ObjectId("57c96a14870ae36ede4d8234"),
ObjectId("57c972b6fc8effecde6cf987")
]
]
}
Why is "Match" field returns empty array?
And why "ReadBy" wrapping the source field with extra array?

a solution is to use $arrayElemAt to get the sub array.
the new query is
db.getCollection('Chats').aggregate([
{
$project:{
Created:1,
Messages:1,
Match:{
$setIntersection:[
{
$arrayElemAt:[
"$Messages.ReadBy",
0
]
},
[
ObjectId("57c96a14870ae36ede4d8085")
]
]
},
ReadBy:"$Messages.ReadBy"
}
}
])
and the result is now
{
"_id" : ObjectId("58136ba83bdddd2d3cd4b3fb"),
"Created" : ISODate("2016-10-28T15:15:52.563Z"),
"Messages" : [
{
"Created" : ISODate("2016-10-28T15:15:52.567Z"),
"ReadBy" : [
ObjectId("57c96a14870ae36ede4d8085"),
ObjectId("57c972b6fc8effecde6cf0fa")
],
"Content" : "Hello"
}
],
"Match" : [
ObjectId("57c96a14870ae36ede4d8085")
],
"ReadBy" : [
[
ObjectId("57c96a14870ae36ede4d8085"),
ObjectId("57c972b6fc8effecde6cf0fa")
]
]
}
{
"_id" : ObjectId("5813ac380a45415df8e7fc08"),
"Created" : ISODate("2016-10-28T15:16:52.563Z"),
"Messages" : [
{
"Created" : ISODate("2016-10-28T15:15:52.567Z"),
"ReadBy" : [
ObjectId("57c96a14870ae36ede4d8234"),
ObjectId("57c972b6fc8effecde6cf987")
],
"Content" : "Hello2"
}
],
"Match" : [ ],
"ReadBy" : [
[
ObjectId("57c96a14870ae36ede4d8234"),
ObjectId("57c972b6fc8effecde6cf987")
]
]
}

Related

Sort query for dynamic array in Mongo DB

I have a collection in MongoDB like below format. Now i want to know how to apply sorting. Please find example of collection below,
{
"_id" : ObjectId("5e5e140f113a6c3970eef3bb"),
"FormId" : "5cd3a0a0cb20953208fcb549",
"FieldsDatas" : [
{
"FieldId" : "4fbcef5b-d60a-4908-a037-5ff085b70709",
"Value" : [
"202003031"
]
},
{
"FieldId" : "708e1baf-fcd0-45fa-b1de-27f34391c35c",
"Value" : [
"202003031"
]
},
{
"FieldId" : "0b563a80-2b0a-4803-ad7f-652a381e134c",
"Value" : [
"New Source",
"Endpoint"
]
},
{
"FieldId" : "15355b82-4fae-4c09-acb4-13f95e8c2d4e",
"Value" : [
"2020-03-03 13:51:17"
]
},
{
"FieldId" : "1e32a283-34a9-4a7b-b851-3e5ac7f93d2c",
"Value" : [
"tets"
]
}
]
}
{
"_id" : ObjectId("5e5e1c89113a6c3970eef3bc"),
"FormId" : "5cd3a0a0cb20953208fcb549"
"FieldsDatas" : [
{
"FieldId" : "708e1baf-fcd0-45fa-b1de-27f34391c35c",
"Value" : [
"202003032"
]
},
{
"FieldId" : "0eca0881-a69b-4db3-b8b1-d74b0a16d4ef",
"Value" : [
"20200303_2#mail.com"
]
},
{
"FieldId" : "2da67714-aaf3-433d-9a86-1b48c75470ec",
"Value" : [
"mani lj"
]
},
{
"FieldId" : "a0b26aac-cad0-4c5e-83b4-9a01ac4ce97a",
"Value" : []
},
{
"FieldId" : "15355b82-4fae-4c09-acb4-13f95e8c2d4e",
"Value" : [
"2020-03-03 14:29:23"
]
}
]
}
For above collection i have date inside the array of objects called FieldsDatas where "FieldId": "15355b82-4fae-4c09-acb4-13f95e8c2d4e" in that same "Value" array has datetime. I want to sort the result based in this datetime.
I have a filter query. How to add sort query for above scenario?
db.getCollection('Collection').find({
"$and":[
{
FieldsDatas: {
$elemMatch:{
FieldId:'955c9843-1535-4df8-a1c4-09430ac9f6ba',
Value: { $ne: ["Contact"] }
}
}
}
]
})
.limit(5)
.skip(30);
Anyone please help me to add sorting for this query like above datetime field.
Any possibilities to achieve this by Stored procedure or functions. Please let me know.
Thanks in advance,
Mani

Combine different collection result into one in Mongo

Below is my query I want the result of shp_tx_survey_with_index and
for each loop collection shp_counties_with_index name1 and name2 together of both this collection. If running this query separate then getting the result but this query gives me nothing. I want result like Range_Township, Survey, Section, abstract, centroid, name_1, name_2.
db.shp_tx_survey_with_index.aggregate(
[
{ $match: { "centroid": { "$ne": null } } },
{ $limit: 5 },
{
$project: {
Range_Township: "$l1surnam",
Survey: "$l4surnam",
Section: "$l1surnam",
abstract: "$abstract_",
centroid: "$centroid"
}
}
]
).forEach((obj) => {
var item = db.shp_counties_with_index.findOne({
geom_geojson: {
$nearSphere: {
$geometry: obj.centroid
}
}
}, { 'name_1': 1, 'name_2': 1 });
});
shp_counties_with_index sample collection
{
"_id" : ObjectId("5846bf55834d5b761f00000a"),
"engtype_2" : "County",
"geom_geojson" : {
"type" : "MultiPolygon",
"coordinates" : [
[
[
[
-73.6516685561232,
34.2445059658098
],
[
-73.6516685623318,
34.2445059757618
],
[
-73.6516685538257,
34.244505973301
],
[
-73.6516685561232,
34.2445059658098
]
]
] ]
},
"name_0" : "United States",
"name_1" : "Michigan",
"name_2" : "Chippewa",
"shape_area" : "0.481851809544",
"shape_leng" : "9.37720288177",
"type_2" : "County",
"validfr_2" : "Unknown",
"validto_2" : "Unknown",
"centroid" : {
"coordinates" : [
-73.65166855807875,
34.244505970785795
],
"type" : "Point"
}
}
shp_tx_survey_with_index sample collection
{
"_id" : ObjectId("5846bf76834d5b761f013fa7"),
"abstract_" : "321.000000000",
"abstract_i" : "322.000000000",
"anum" : "443962",
"area" : "0.0000666764235294",
"geom" : "01060000000100000001030000000100000008000000EC90DE47A07659C0F062332AEA813E403471FBB0A17759C06082096CE6813E4034A2C2ABA17759C0700AAF2731823E40B49BADAAA17759C09092F09440823E401C588E90A17759C000B4279A6A823E400019834C677559C02026721261823E403073564B677559C080C77880E6813E40EC90DE47A07659C0F062332AEA813E40",
"geom_geojson" : {
"type" : "MultiPolygon",
"coordinates" : [
[
[
[
-73.6517272344497,
34.2444627902475
],
[
-73.6517271719931,
34.2444627964974
],
[
-73.6517271718375,
34.2444627914072
],
[
-73.6517272344497,
34.2444627902475
]
]
]
]
},
"geom_text" : "MULTIPOLYGON(((-73.6517272344497 34.2444627902475,-73.6517271719931 34.2444627964974,-73.6517271718375 34.2444627914072,-73.6517272344497 34.2444627902475)))",
"gid" : "271508",
"l1surnam" : "TEMPLETON, J S",
"l2block" : null,
"l3surnum" : "4",
"l4surnam" : null,
"perimeter" : "0.0735082380545",
"probflag" : "0",
"shape_area" : "0.0000666764230571",
"shape_leng" : "0.0735082374282",
"centroid" : {
"coordinates" : [
-73.6517272031436,
34.24446279337245
],
"type" : "Point"
}
}
Thanks in advance.
When you want to combine information from 2 collections in a aggregation pipeline you can use the $lookup operator.
This operator is available from MongoDB 3.2 and up.

MongoDB finding all subdocuments where subDocument _ids like "string"

Sample document structure is like:
{
"_id" : "https://docs.mongodb.org/manual",
"collection" : {
"_id" : "collection",
"urls" : [
"https://docs.mongodb.org/manual/c1",
"https://docs.mongodb.org/manual/c2"
]
},
"collectionNew" : {
"_id" : "collection1",
"urls" : [
"https://docs.mongodb.org/manual/c1New",
"https://docs.mongodb.org/manual/c2New"
]
},
"log" : {
"_id" : "log",
"urls" : [
"https://docs.mongodb.org/manual/l1",
"https://docs.mongodb.org/manual/l2"
]
}
}
I have multiple such documents in my collection.
After finding document by
db.AutoSearch.find({"_id": "https://docs.mongodb.org/manual"})
i want to search all subdocuments under this with name like "collection"
SOLUTION
I changed my document structure to:
{
"_id" : "https://docs.mongodb.org/manual",
"contents" : [
{
"_id" : "connect",
"urls" : [
"https://docs.mongodb.org/manual/search/?query=connect"
]
},
{
"_id" : "connection",
"urls" : [
"https://docs.mongodb.org/manual/search/?query=connection",
"https://docs.mongodb.org/manual/search/?query=connection%20pymongo"
]
}
{
"_id" : "list",
"urls" : [
"https://docs.mongodb.org/manual/search/?query=listfiles",
"https://docs.mongodb.org/manual/search/?query=listdatabases",
"https://docs.mongodb.org/manual/search/?query=listcommands"
]
},
{
"_id" : "log",
"urls" : [
"http://docs.mongodb.org/manual/tutorial/rotate-log-files/",
"http://docs.mongodb.org/manual/reference/log-messages/"
]
},
{
"_id" : "index",
"urls" : [
"https://docs.mongodb.org/manual/search/?query=index-related%20commands"
]
}
]}
Then by using mongoDB aggregate query
db.AutoSearch.aggregate([{$match:{ "_id": "https://docs.mongodb.org/manual"}},
{$unwind: '$contents'},
{$match:{"contents._id":/connect/}}])
I got the desired output.

MongoDB: Find a document that matches a condition in all its subdocument

I am trying to write a mongo query to fetch the result that satisifes a condition on all its subdocument,
1. {
"_id" : 1,
"data" : [
{
"Id" : "513",
"Nom" : "alouale pfouga",
}
],
"campaigns" : [
{
"user" : "1",
"latest" : NumberInt(0),
"postcode" : [
[
]
],
},
{
"user" : "2",
"latest" : NumberInt(1),
"postcode" : [
{
"id" : "772",
"name" : "xxx",
}
],
}
],
}
2. {
"_id" : 2,
"data" : [
{
"Id" : "514",
"Nom" : "pfouga remi",
}
],
"campaigns" : [
{
"user" : "1",
"latest" : NumberInt(0),
"postcode" : [
[
]
],
},
],
}
I need to find the record that has "Postcode" array is empty.
As far as I understand query like this: db.users.find({"campaigns.postcode":[]}) gives me both records, but i need only record 2 , because record 1 has postcode node in one sub documents, Please anyone help me !!!
This would give you the answer:
db.test.find({ 'campaigns.postcode': { $size: 0 } } )
but in your case 'campaigns.postcode' has an empty array in it and that means the size is not 0, its 1
You should remove your empty array
"postcode" : [
[
]
],
should be
"postcode" : []
Updated:
After spending some time on the question I realized the problem
For converting "postcode" : [[]] to "postcode" : [] you can use this code:
db.test.find({ 'campaigns.postcode': []} ).forEach(function(item){
for(var i0 = 0; i0 < item.campaigns.length; i0++)
{
if(item.campaigns[i0].postcode[0].length == []) item.campaigns[i0].postcode = [];
}
db.test.update({'_id' : item._id}, item);
});
after that you can find your proper result with:
db.test.find({ 'campaigns.postcode': { $size: 0 }, 'campaigns': { $size: 1 } } )
In your json structure it contains
"postcode" : [
[
]
],
So I tried some but not found exact what you want in expected results I found postcode data where all postcode was empty using following aggregation
db.collectionName.aggregate({"$unwind":"$campaigns"},
{"$unwind":"$campaigns.postcode"},
{"$match":{"campaigns.postcode":{"$size":0}}})

Mongo:count the total number of elements in array depending on condition

I am new to mongoDB . I have aware of some basic queries of mongoDb but not advanced.
My document looks like following :
{
"_id" : ObjectId("5289deaa84aedcc100228259"),
"gender" : "male",
"intrest" : [
{
"userId" : ObjectId("5286294984ae18ac5d19af36"),
"timestamp" : ISODate("2013-11-18T09:32:38.040Z"),
"status" : "Pending"
},
{
"userId" : ObjectId("5286295984ae18ac5d19af37"),
"timestamp" : ISODate("2013-11-18T09:33:17.493Z"),
"status" : "Pending"
}
],
"intrestAccepted" : [ ],
"intrestCancled" : [ ],
"intrestDeclined" : [ ],
"intrestReceived" : [
ObjectId("5286294984ae18ac5d19af36"),
ObjectId("5286295984ae18ac5d19af37")
],
"owner" : ObjectId("5286293284ae18ac5d19af35"),
"postDesc" : "gggg",
"tags" : [
"ggg"
]
}
{
"_id" : ObjectId("5289dea084aedcc100228258"),
"gender" : "female",
"intrest" : [
{
"userId" : ObjectId("5286294984ae18ac5d19af36"),
"timestamp" : ISODate("2013-11-18T09:32:42.934Z"),
"status" : "Pending"
},
{
"userId" : ObjectId("5286295984ae18ac5d19af37"),
"timestamp" : ISODate("2013-11-18T09:33:18.520Z"),
"status" : "Pending"
}
],
"intrestAccepted" : [ ],
"intrestCancled" : [ ],
"intrestDeclined" : [ ],
"intrestReceived" : [
ObjectId("5286294984ae18ac5d19af36"),
ObjectId("5286295984ae18ac5d19af37")
],
"owner" : ObjectId("5286293284ae18ac5d19af35"),
"postDesc" : "asdf",
"tags" : [
"asdf"
]
}
{
"_id" : ObjectId("5289dec984aedcc10022825a"),
"gender" : "male",
"intrest" : [
{
"userId" : ObjectId("5286295984ae18ac5d19af37"),
"timestamp" : ISODate("2013-11-18T09:33:20.996Z"),
"status" : "Pending"
}
],
"intrestAccepted" : [ ],
"intrestCancled" : [ ],
"intrestDeclined" : [ ],
"intrestReceived" : [
ObjectId("5286295984ae18ac5d19af37")
],
"owner" : ObjectId("5286294984ae18ac5d19af36"),
"postDesc" : "fff",
"tags" : [
"fff"
]
}
I want to find totalcount for intrestReceived[] whose owner is ObjectId("5286293284ae18ac5d19af35")
What query am I supposed to write. Please help .
You could try something simple like this:
intrestReceived_length = 0
db.col.find({ _id: ObjectId("5286293284ae18ac5d19af35") }).forEach( function( doc ){
intrestReceived_length = doc.intrestReceived.length;
});
The find will extract only the document that matches the ObjectId you provided and then we use a forEach on the cursor to iterate over all of the (one) results. Within the forEach callback, we just use a JavaScript array.length command to extract the size of the array.
You could also output only the intrestReceived array by providing a projection in your find command:
db.col.find({ _id: ObjectId("5286293284ae18ac5d19af35") }, { "intrestReceived": 1 })...
This will return the same document but it will only contain the _id and intrestReceived attributes.