mongodb Can't get the query to work - mongodb

I'm trying to do a query in mongodb but I can't get it to work.
My document looks something like this.
{
"_id" : ObjectId("5305e54133e65b7341d63af3"),
"clients" : [
{
"aggregations" : {
"department" : [
"department1",
"department3"
],
"customer" : "customer2"
},
"lastLogin" : ISODate("2014-02-26T09:41:56.445Z"),
"locale" : "en"
"name" : "Test",
"validFrom" : null,
"validTo" : null,
"visiting" : {
"phone" : "031-303030",
"company" : "MyCompany",
"office" : [
"jag är ett test",
"lite mer data"
],
"country" : "Norge"
}
},
{
"approvedEmailSent" : true,
"lastLogin" : ISODate("2014-03-01T15:27:12.252Z"),
"locale" : "en",
"name" : "Test2",
"visiting" : {
"phone" : "031-307450",
"company" : "Other Company",
"branch" : "Advertising agency"
}
}
],
"firstname" : "Greger",
"lastname" : "Aronsson",
"username" : "TheUsername"
}
As you can see a user can have many clients. They are matched by name. The clients have visiting.company but sometimes this will not be the case.
I want to query where the clients.name is Test and regexp for visting.company and also firstname, lastname. If I'm logged in at Test2 I don't want hits on visiting.company "MyCompany". Hope this makes sense!

You can write query like :
db.visitCompany2.find({ $or : [
{'clients.name': 'Test2'}, //Company name
{'clients.visiting.company': {
$regex: /Other/g //Your visiting company regex
}},
{firstname: "Greger"},
{"lastname": "Aronsson}"
]}, {
'clients.$': 1, //projection for clients
firstname: 1,
lastname: 1
});
Output:
{
"_id": ObjectId("5305e54133e65b7341d63af3"),
"clients": [{
"approvedEmailSent": true,
"lastLogin": ISODate("2014-03-01T15:27:12.252Z"),
"locale": "en",
"name": "Test2",
"visiting": {
"phone": "031-307450",
"company": "Other Company",
"branch": "Advertising agency"
}
}],
"firstname": "Greger",
"lastname": "Aronsson"
}

Related

How to get multiple documents from one document in mongoDB?

I have multiple documents that needs to be queried from mongodb. Requirement is such that I need the nested array of documents has to be in a separate document under certain conditions. I have given a document sample for instance. In that I have an array of objects called cars, the output have to be such that the status is still inprogress and the key: parent_company is true then the objects that has parent_company_id equal to the _id of the parent_company: true and at least one of their model array has "v12".
This might be confusing when explaining but please check on the document in db and the expected result, you'd get an idea on the requirement here.
If you take a look at the second JSON below, you can see those are the same Documents with different array of cars with certain conditions and that is how am expecting the results to be from the actual data from a collection
So the condition is status has to be "inprogress" for "parent_company" : true and if any object under cars array has v12 in model then I need to get those documents that has the same parent_company_id.
Documents in db:
{
"_id" : ObjectId("63a8808652f40e1d48a3d1d7"),
"name" : "A",
"description" : null,
"cars" : [
{
"id" : "63a8808c52f40e1d48a3d1da",
"owner" : "John Doe",
"purchase_date" : "2022-12-25,
"status" : "inprogress",
"parent_company" : true,
"parent_company_id" : "63a8808c52f40e1d48a3d1da",
"model" : [
]
},
{
"id" : "63a880a552f40e1d48a3d1dc",
"owner" : "John Doe 1",
"purchase_date" : "2022-12-25,
"parent_company" : false,
"parent_company_id" : "63a8808c52f40e1d48a3d1da",
"model" : [
"v12"
]
},
{
"id" : "63a880f752f40e1d48assddd"
"owner" : "John Doe 1",
"purchase_date" : "2022-12-25,
"parent_company" : false,
"parent_company_id" : "63a8808c52f40e1d48a3d1da",
"model" : [
]
},
{
"id" : "63a880f752f40e1d48a3d207"
"owner" : "John Doe 11",
"dt" : "2022-12-25,
"status" : "inprogress",
"parent_company" : true,
"parent_company_id" : "63a880f752f40e1d48a3d207",
"model" : [
"v12"
]
},
{
"id" : "63a880f752f40e1d48agfddd"
"owner" : "John Doe 112",
"dt" : "2022-12-25,
"status" : "inprogress",
"parent_company" : true,
"parent_company_id" : "63a880f752f40e1d48agfddd",
"model" : [
]
}
]
}
Result I need
[
{
"_id" : ObjectId("63a8808652f40e1d48a3d1d7"),
"name" : "A",
"description" : null,
"cars" : [
{
"id" : "63a8808c52f40e1d48a3d1da",
"owner" : "John Doe",
"purchase_date" : "2022-12-25,
"status" : "inprogress",
"parent_company" : true,
"parent_company_id" : "63a8808c52f40e1d48a3d1da",
"model" : [
]
},
{
"id" : "63a880a552f40e1d48a3d1dc",
"owner" : "John Doe 1",
"purchase_date" : "2022-12-25,
"parent_company" : false,
"parent_company_id" : "63a8808c52f40e1d48a3d1da",
"model" : [
"v12"
]
},
{
"id" : "63a880f752f40e1d48assddd"
"owner" : "John Doe 1",
"purchase_date" : "2022-12-25,
"parent_company" : false,
"parent_company_id" : "63a8808c52f40e1d48a3d1da",
"model" : [
]
}
]
},
{
"_id" : ObjectId("63a8808652f40e1d48a3d1d7"),
"name" : "A",
"description" : null,
"cars" : [
{
"id" : "63a880f752f40e1d48a3d207"
"owner" : "John Doe 11",
"dt" : "2022-12-25,
"status" : "inprogress",
"parent_company" : true,
"parent_company_id" : "63a880f752f40e1d48a3d207",
"model" : [
"v12"
]
}
]
}
]
If I understand correctly, here's one way to do it.
db.collection.aggregate([
{"$unwind": "$cars"},
{
"$group": {
"_id": "$cars.parent_company_id",
"root": {"$first": "$$ROOT"},
"cars": {"$push": "$cars"}
}
},
{
"$replaceWith": {
"$mergeObjects": [
"$root",
{"cars": "$cars"}
]
}
},
{
"$match": {
"cars.parent_company": true,
"cars.model": "v12"
}
}
])
Try it on mongoplayground.net.

How to write following queries in MongoDB using aggregate?

Retrieve films with an actor living in "Spain",
Retrieve films with actor details.
Collections are:
db.actor.insert([{ "actorId" : "5", "firstName" : "Ritik", "lastName" : "Roshan", "address" : { "street" : "GM Road", "city" : "Guwahati", "state" : "Aasam", "country" : "India", "pincode" : "145145" }, "contactDetails" : { "email" : "Ritik.roshan#gmail.com", "phoneno" : "9874584" }, "age" : "52" }])
db.film.insert([{ "filmId" : "10","title" : "Doshti Ka Karishma", "releaseOfYear" : "2001", "category" : ["advanture","Romantic"],
"actor" : [{ "firstName" : "Ritik", "lastName" : "Roshan" },{ "firstName" : "Karishma", "lastName" : "Kapoor" }],
"director" : [{ "firstName" : "Satish", "lastName" : "Ambike" }],
"releaseDetails" : { "place" : "Rajasthan", "date" : ISODate("2001-05-18T15:14:08.023Z"), "rating" : "C"}}])
You can use $lookup to join two collection
db.film.aggregate([
{ $match: { "releaseDetails.place": "Rajasthan" } },
{
"$lookup": {
"from": "actor",
"let": {
actor: "$actor"
},
"pipeline": [
{
$match: {
$expr: {
$and: [
{ $in: [ "$firstName", "$$actor.firstName" ] },
{ $in: [ "$lastName", "$$actor.lastName" ] }
]
}
}
}
],
"as": "joinActors"
}
}
])
Working Mongo playground
Note : You are saving firstname and lastname as reference in film collection. But combination of firstname and lastname are not always unique, Better you save _id of actor into the film collection's actor section.
something like this Save ref id

Getting an array out of the input using aggregate

My input file looks like this:
[
{
"type" : "asdf",
"properties" : {
"Name" : "First center",
"Code" : "ABCD",
"Address" : "Emmastr 14",
"City" : "Rotterdam",
"Postcode" : 55968,
}
},
{
"type" : "qwer",
"properties" : {
"Name" : "Second center",
"Code" : "OTHER",
"Address" : "Havenstraat 15",
"City" : "Rotterdam",
"Postcode" : 88767,
}
},
{
"type" : "zxcv",
"properties" : {
"Name" : "Third center",
"Code" : "ABCD",
"Address" : "Kerkstraat 16",
"City" : "Amsterdam",
"Postcode" : 33948,
}
},
{
"type" : "tyiu",
"properties" : {
"Name" : "Fourth center",
"Code" : "ABCD",
"Address" : "Zeestraat 17",
"City" : "Amsterdam",
"Postcode" : 56475,
}
}
]
I've been tasked to present this information grouped per city (a document for each city).
Only the items that have Code="ABCD" should appear in the output.
Output should be ordered by city name (_id).
Output should be written to a new collection.
So the output I'm looking for is something like this:
_id: "Amsterdam",
center: [
{"Name": "Third center" , "Postcode": 33948, "Address": "Kerkstraat 16"},
{"Name": "Fourth center" , "Postcode": 56475, "Address": "Zeestraat 17"}
]
_id: "Rotterdam",
center: [
{"Name": "First center" , "Postcode": 55968, "Address": "Emmastr 14"}
]
This little snippet filter by "ABCD", groups by city and writes the output to a new collection.
db.centers.aggregate ([
{$match: {"properties.Code": "ABCD"}}
,{ $group: {_id: "$properties.City"}}
,{ $out: "newColl"}
])
But I'm not getting much further because of lack of hands on experience.
I struggle getting an array out of something that's not an array in the input. Is there anyone that could help?
$push to make array of required fields
$sort by _id in ascending order
db.centers.aggregate([
{ $match: { "properties.Code": "ABCD" } },
{
$group: {
_id: "$properties.City",
center: {
$push: {
Name: "$properties.Name",
Postcode: "$properties.Postcode",
Address: "$properties.Address"
}
}
}
},
{ $sort: { _id: 1 } },
{ $out: "newColl" }
])
Playground

MongoDB Use $group for the subset after $group

I just learned mongoDB, I am trying to find some repeat customer info through my customer database.
The sample collection:
{
"_id" : ObjectId("5b7617e48146d8bae"),
"amazon_id" : "112",
"date" : "2018-01-25T18:40:55-08:00",
"email" : "xxxxx#marketplace.amazon.com",
"buy_name" : "xxxxx",
"sku" : "NPC-50",
"qty" : 8,
"price" : 215.92,
"reci_name" : "XXXXX",
"street1" : "XXXXX",
"street2" : "",
"street3" : "",
"city" : "XXXXX",
"state" : "XXXXX",
"zip_code" : "XXXXXX"
}
{
"_id" : ObjectId("5b761712e48146d8bae"),
"amazon_id" : "114",
"date" : "2018-01-27T18:40:55-08:00",
"email" : "xxxxx#marketplace.amazon.com",
"buy_name" : "xxxxx",
"sku" : "ABC",
"qty" : 1,
"price" : 19.99,
"reci_name" : "XXXXX",
"street1" : "XXXXX",
"street2" : "",
"street3" : "",
"city" : "XXXXX",
"state" : "XXXXX",
"zip_code" : "XXXXXX"
}
I group all customer info by their email id, and here is my code:
db.getCollection('order').aggregate([
{ $group: { _id: "$email",
OrderInfo: {$push: {orderId: "$amazon_id", sku: "$sku", qty: "$qty", price:"$price"
}},
CustomerInfo: {$addToSet: {buyName: "$buy_name",reName: "$reci_name", email: "$email", street1: "$street1",
street2: "$street2", city: "$city", state: "$state", zipCode: "$zip_code"} }
}},
{ $project: {_id: 1, OrderInfo: 1, CustomerInfo:1, total_price:{$sum: "$OrderInfo.price"} }},
{ $match: {total_price: {$gt:100} } },
{ $sort: {total_price:-1}},
], { allowDiskUse: true } );
It shows me the result:
{
"_id" : "xxxxxxx#marketplace.amazon.com",
"OrderInfo" : [
{
"orderId" : "112",
"sku" : "NPC-50",
"qty" : 8,
"price" : 215.92
},
{
"orderId" : "112",
"sku" : "NPC-50",
"qty" : 1,
"price" : 26.99
},
{
"orderId" : "114",
"sku" : "NPC-50",
"qty" : 1,
"price" : 26.99
},
{
"orderId" : "114",
"sku" : "ABC",
"qty" : 1,
"price" : 19.99
},
{
"orderId" : "116",
"sku" : "ABC",
"qty" : 1,
"price" : 19.99
},
],
"CustomerInfo" : [
{
"buyName" : "xxxxxxxxx",
"reName" : "xxxxxxxxxxxx",
"email" : "xxxxxxxxxxxx#marketplace.amazon.com",
"street1" : "xxxxxxxxxxx",
"street2" : "",
"city" : "xxxxxxxxxx",
"state" : "xxxxxxxxxxxx",
"zipCode" : "xxxxxxxxxx"
},
{
"buyName" : "xxxxxxxxxx",
"reName" : "xxxxxx",
"email" : "xxxxxxxx#marketplace.amazon.com",
"street1" : "xxxxxxxxxxx",
"street2" : "",
"city" : "xxxxx",
"state" : "xxxx",
"zipCode" : "xxxxxxxx"
}
],
"total_price" : 309.88
}
However, I want to group the sku and sum up the qty and price in the OrderInfo Set. My expected output is something like:
{
"OrderInfo" : [
{
"sku": "NPC-50",
"qty": 10,
"price": 269.9
},
{
"sku": "ABC",
"qty": 2,
"price": 39.98
},
],
"CustomerInfo" : [
{
"buyName" : "xxxxxxxxx",
"reName" : "xxxxxxxxxxxx",
"email" : "xxxxxxxxxxxx#marketplace.amazon.com",
"street1" : "xxxxxxxxxxx",
"street2" : "",
"city" : "xxxxxxxxxx",
"state" : "xxxxxxxxxxxx",
"zipCode" : "xxxxxxxxxx"
},
{
"buyName" : "xxxxxxxxxx",
"reName" : "xxxxxx",
"email" : "xxxxxxxx#marketplace.amazon.com",
"street1" : "xxxxxxxxxxx",
"street2" : "",
"city" : "xxxxx",
"state" : "xxxx",
"zipCode" : "xxxxxxxx"
}
],
"total_price" : 309.88
}
Any Help will be appreciated.
You can use below aggregation.
db.order.aggregate([
{"$group":{
"_id":{"email":"$email","sku":"$sku"},
"qty":{"$sum":"$qty"},
"price":{"$sum":"$price"},
"CustomerInfo":{
"$addToSet":{
"buyName":"$buy_name",
"reName":"$reci_name",
"email":"$email",
"street1":"$street1",
"street2":"$street2",
"city":"$city",
"state":"$state",
"zipCode":"$zip_code"
}
}
}},
{"$group":{
"_id":"$_id.email",
"OrderInfo":{"$push":{"sku":"$_id.sku","qty":"$qty","price":"$price"}},
"total_price":{"$sum":"$price"},
"CustomerInfo":{"$first":"$CustomerInfo"}
}},
{"$match":{"total_price":{"$gt":100}}},
{"$sort":{"total_price":-1}}
])
You can try below aggregation
db.collection.aggregate([
{ "$group": {
"_id": {
"email": "$email",
"sku": "$sku"
},
"CustomerInfo": {
"$addToSet": {
"buyName": "$buy_name",
"otherFields": "$otherFields",
}
},
"price": { "$sum": "$price" },
"qty": { "$sum": "$qty" }
}},
{ "$group": {
"_id": "$_id.email",
"CustomerInfo": { "$first": "$CustomerInfo" },
"OrderInfo": {
"$push": {
"sku": "$_id.sku",
"qty": "$qty",
"price": "$price"
}
}
}}
])

How to publish posts depend on privacy?

I need to publish a queue from collection Posts depending of privacy. But I don't have any idea how to get this. I've draw mindmap of main concept what I try to realize:
Input:
var currentUser = "Andrey";
Events.find();
Output:
[
{
//it's going to output, becouse I've created this post
"_id" : "1",
"createdBy" : "Andrey",
"private" : true,
"title" : "",
"text": "",
"members" : [
"Sheldon", "Mike"
]
},
{
//it's going to output, becouse this post not private
"_id" : "2",
"createdBy" : "Sheldon",
"private" : false,
"title" : "",
"members" : []
},
{
//it's going to output, becouse I'm one of members'
"_id" : "3",
"createdBy" : "Mike",
"private" : true,
"title" : "",
"text": "",
"members" : [
"Andrey"
]
},
{
//it's NOT going to output, becouse it's private post, I'm not the member or author
"_id" : "4",
"createdBy" : "Ana",
"private" : true,
"title" : "",
"text": "",
"members" : [
"Sheldon"
]
},
]
Expected result:
[
{
"_id" : "1",
"createdBy" : "Andrey",
"private" : true,
"title" : "",
"text": "",
"members" : [
"Sheldon", "Mike"
]
},
{
"_id" : "2",
"createdBy" : "Sheldon",
"private" : false,
"title" : "",
"text": "",
"members" : []
},
{
"_id" : "3",
"createdBy" : "Mike",
"private" : true,
"title" : "",
"text": "",
"members" : [
"Andrey"
]
}
]
But this idea can be wrong at all, maybe you have another way?
I am not sure if this is the right approach but probably I'd try something like that if I face this issue. (By the way I'd use userId instead of names. If you used names in order to explain your aim, please ignore this comment)
As long as I remember, you can return multiple query results like that
return [
Result1,
Result2,
]
For the public posts, no need to worry I guess. Just returning the ones with private: false is sufficient.
For the private ones, I'd use userId as parameter and try this composite publication:
Meteor.publish('posts', function postPublication(userId) {
return [
Posts.find({
$and: [{
$or: [
{_id: userId},
{memberId: {$in: userId}}
]},
{private: {$eq: true}}
]}), // => should return private posts created or commented by member
Posts.find({private: {$eq: false}}) // => should return public ones
];
}
Then do the subscription with userId
Meteor.subscribe('posts', userId);
This code how I solved this task, with $or $and. But not sure too, if it's a best solution. But I get expected result.
Meteor.publish('posts', function(currentUser) {
selector = {
$or : [
{ $and : [ {'private': true, 'members': currentUser} ] },
{ $and : [ {'private': true, 'author': currentUser} ] },
{ $and : [ {'private': false, 'author': currentUser} ] },
{ $and : [ {'private': undefined} ] },
{ $and : [ {'private': false} ] },
]
}
return Posts.find(selector);
});