Mongoose Query: Find an element inside an array - arrays

Mongoose/Mongo noob here:
My Data
Here is my simplified data, each user has his own document
{ "__v" : 1,
"_id" : ObjectId( "53440e94c02b3cae81eb0065" ),
"email" : "test#test.com",
"firstName" : "testFirstName",
"inventories" : [
{ "_id" : "active",
"tags" : [
"inventory",
"active",
"vehicles" ],
"title" : "activeInventory",
"vehicles" : [
{ "_id" : ObjectId( "53440e94c02b3cae81eb0069" ),
"tags" : [
"vehicle" ],
"details" : [
{ "_id" : ObjectId( "53440e94c02b3cae81eb0066" ),
"year" : 2007,
"transmission" : "Manual",
"price" : 1000,
"model" : "Firecar",
"mileageReading" : 50000,
"make" : "Bentley",
"interiorColor" : "blue",
"history" : "CarProof",
"exteriorColor" : "blue",
"driveTrain" : "SWD",
"description" : "test vehicle",
"cylinders" : 4,
"mileageType" : "kms" } ] } ] },
{ "title" : "soldInventory",
"_id" : "sold",
"vehicles" : [],
"tags" : [
"inventory",
"sold",
"vehicles" ] },
{ "title" : "deletedInventory",
"_id" : "deleted",
"vehicles" : [],
"tags" : [
"inventory",
"sold",
"vehicles" ] } ] }
As you can see, each user has an inventories property that is an array that contains 3 inventories (activeInventory, soldInventory and deletedInventory)
My Query
Given an user's email a a vehicle ID, i would like my query to go through find the user's activeInventory and return just the vehicle that matches the ID. Here is what I have so far:
user = api.mongodb.userModel;
ObjectId = require('mongoose').Types.ObjectId;
return user
.findOne({email : params.username})
.select('inventories')
.find({'title': 'activeInventory'})
//also tried
//.where('title')
//.equals('activeInventory')
.exec(function(err, result){
console.log(err);
console.log(result);
});
With this, result comes out as an empty array. I've also tried .find('inventories.title': 'activeInventory') which strangely returns the entire inventories array. If possible, I'd like to keep the chaining query format as I find it much more readable.
My Ideal Query
return user
.findOne({email : params.username})
.select('inventories')
.where('title')
.equals('activeInventory')
.select('vehicles')
.id(vehicleID)
.exec(cb)
Obviously it does not work but it can give you an idea what I'm trying to do.

Using the $ positional operator, you can get the results. However, if you have multiple elements in the vehicles array all of them will be returned in the result, as you can only use one positional operator in the projection and you are working with 2 arrays (one inside another).
I would suggest you take a look at the aggregation framework, as you'll get a lot more flexibility. Here's an example query for your question that runs in the shell. I'm not familiar with mongoose, but I guess this will still help you and you'd be able to translate it:
db.collection.aggregate([
// Get only the documents where "email" equals "test#test.com" -- REPLACE with params.username
{"$match" : {email : "test#test.com"}},
// Unwind the "inventories" array
{"$unwind" : "$inventories"},
// Get only elements where "inventories.title" equals "activeInventory"
{"$match" : {"inventories.title":"activeInventory"}},
// Unwind the "vehicles" array
{"$unwind" : "$inventories.vehicles"},
// Filter by vehicle ID -- REPLACE with vehicleID
{"$match" : {"inventories.vehicles._id":ObjectId("53440e94c02b3cae81eb0069")}},
// Tidy up the output
{"$project" : {_id:0, vehicle:"$inventories.vehicles"}}
])
This is the output you'll get:
{
"result" : [
{
"vehicle" : {
"_id" : ObjectId("53440e94c02b3cae81eb0069"),
"tags" : [
"vehicle"
],
"details" : [
{
"_id" : ObjectId("53440e94c02b3cae81eb0066"),
"year" : 2007,
"transmission" : "Manual",
"price" : 1000,
"model" : "Firecar",
"mileageReading" : 50000,
"make" : "Bentley",
"interiorColor" : "blue",
"history" : "CarProof",
"exteriorColor" : "blue",
"driveTrain" : "SWD",
"description" : "test vehicle",
"cylinders" : 4,
"mileageType" : "kms"
}
]
}
}
],
"ok" : 1
}

getting the chaining query format ... i dont know how to parse it but, what you are searching for is projection, you should take a look to http://docs.mongodb.org/manual/reference/operator/projection/
it would probably look like this :
user.findOne({email: params.username}, {'inventories.title': {$elemMatch: "activeInventory", 'invertories.vehicle.id': $elemMatch: params.vehicleId}, function(err, result) {
console.log(err);
console.log(result);
})

Related

Problems with JSON

I'm trying to Order in ascending order the requirements that are not between 25,000 and 30,000. The requirements are information of an array which is inside of a document and the condition is that they can't be in that determined range. I'm trying to do it properly but i can't find any information about this.
Document structure
{
"_id" : ObjectId("5ec73abebd7e4d618a05734e"),
"code" : "A47",
"title" : "Software engineer",
"description" : "Analyze, design, create, test computer and software systems.",
"city" : "Madrid",
"date" : ISODate("2020-05-22T02:36:46.271Z"),
"salary" : 30000.0,
"active" : true,
"requirements" : [
"python",
"java",
"html5",
"C++",
"C#"
],
"info_company" : {
"cif" : "A00000000",
"name" : "FUTURE S.A",
"location" : "Madrid",
"web" : "www.future.es",
"about" : "We are a leading company in new technologies."
},
"pyme" : true
}
db.offers.update(
{ $ne : [ salary: {
$gte : 25000,
$lte : 35000 ]
} },
{
$push : {
requirements: {
$each : [] ,
$sort : 1
}
}
}
,
{
multi : true
} )

How to group records based on array elements using MongoDB

I have a data collection which contains a set of records in the following format.
{
"_id" : 22,
"title" : "3D User Interfaces with Java 3D",
"isbn" : "1884777902",
"pageCount" : 520,
"publishedDate" : ISODate("2000-08-01T07:00:00Z"),
"thumbnailUrl" : "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/barrilleaux.jpg",
"longDescription" : "Description",
"status" : "PUBLISH",
"authors" : [
"Jon Barrilleaux"
],
"categories" : [
"Java",
"Computer Graphics"
]
},
{
"_id" : 23,
"title" : "Specification by Example",
"isbn" : "1617290084",
"pageCount" : 0,
"publishedDate" : ISODate("2011-06-03T07:00:00Z"),
"thumbnailUrl" : "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/adzic.jpg",
"status" : "PUBLISH",
"authors" : [
"Gojko Adzic"
],
"categories" : [
"Software Engineering"
]
}
Please note that the 'categories' is an array.
I want to count the published books for each category. I tried the following solution, but it treated the entire array as one group.
db.books.aggregate([
{
$group:{_id:"$categories", total:{$sum:1}}
}
])
Instead of so, I want to count the number of records for each individual category value inside 'categories' array.
You should first use $unwind which outputs one document for each element in the array.
db.books.aggregate([
{
$unwind : "$categories"
},
{
$group : { _id : "$categories", total: { $sum: 1 } }
}
])

MongoDB query to retrieve a specific value from the document located in a array

I am trying to make a request in a document with mongodb.
In this document
{
"_id" : ObjectId("5bd19a92da24674fdabd26b6"),
"search" : "try",
"name" : "try",
"email" : "yes#gmail.com",
"password" : "$2a$10$YIRuApqDy/L8HU7R1k2SB.aC2hqH8xFDbl3/muF7PsoN6/SGzsH4q",
"color" : 0,
"profil" : "",
"banner" : "",
"desc" : "",
"date" : 45587899,
"friend" : [
{
"id" : ObjectId("5bcee588ae409f434d35c76c")
}
],
"groupes" : [ ]
}
I'm looking to get just the id in friend, not all of the document just 1 id in friend with where i try this :
db.users.find({$and:[{"friend.id":"ObjectId(5bcee588ae409f434d35c76c)"},{"search":"try"}]})
It's not working i got no result.
Thank you for helping me.
I am not 100% sure I do understand your question properly. You should be able to query the described document via the following query:
find(
/* query by 'search' and the specific friend-id */
{'friend.id': ObjectId("5bcee588ae409f434d35c76c"), search: 'try'},
/* return only that 'friend' element which matches the queried 'friend-id' */
{_id:0, friend:{$elemMatch:{id:ObjectId("5bcee588ae409f434d35c76c")}}}
)
You get the following result:
{
"friend" : [
{
"id" : ObjectId("5bcee588ae409f434d35c76c")
}
]
}
db.users.find({
friend: {
$elemMatch: {
id: ObjectId("5bcee588ae409f434d35c76c")
}
},
search: 'try'
})

Not able to write the query in mongo for array element match?

I am working on project on which I had to make recommendation system for users in website.I am new to Mongodb.
I want to retrieve the names/id of users who have "frnds.type"=1 in below code.
{
"_id" : ObjectId("56a9fcc15b4e12369150d6ef"),
"name" : "Udit",
"venue" : {
"state" : "Rajasthan",
"city" : "Jaipur",
"ll" : [
"26.9000",
"75.8000"
]
},
"lsv" : [
0.14,
0.18,
0.24,
0.17,
0.05,
0.17,
0.05
],
"username" : "udit",
"frnds" : [
{
"id" : "amit",
"type" : 1
},
{
"id" : "nakul",
"type" : 0
},
{
"id" : "verma",
"type" : 1
}
]
}
I have written one query but it is giving wrong results
db.users.find({"username":"udit"},{"frnds":{"$elemMatch":{"type":1}}}).pretty()
I want result in this manner :
[
{
"id":"amit",
"type":1
},
{
"id":"verma",
"type":1
}
]
Try with Aggregation Framework as below.
db.users.aggregate([{
$match: {username: 'udit'},
{$unwind: '$frnds'},
{$match: {'frnds.type': 1}},
{$group: {frnds: {$push: "$frnds"}}
}]);

How to get just element that matches query in a mongo find operation? [duplicate]

This question already has answers here:
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 8 years ago.
i've got some documents like this:
{
"name" : "xxx",
"address" : " ",
"mail" : "",
"url" : "",
"pos" : {
"lat" : yyy,
"lng" : zzz
},
"rooms" : [
{
"_id" : ObjectId("540ce3f8e4b016292085b387"),
"supplier" : "s1",
"price" : 41000,
"details" : [
{
"price" : 25200,
"key" : "2-1"
},
{
"price" : 15800,
"key" : "2-0"
}
]
},
{
"_id" : ObjectId("540ce3f8e4b016292085b3fd"),
"supplier" : "s2",
"price" : 44900,
"details" : [
{
"price" : 27000,
"key" : "2-1"
},
{
"price" : 17900,
"key" : "2-0"
}
]
},
{
"_id" : ObjectId("540ce3f8e4b016292085b53d"),
"supplier" : "s3",
"price" : 53500,
"details" : [
{
"price" : 32100,
"key" : "2-1"
},
{
"price" : 21400,
"keykey" : "2-0"
}
]
}
]
}
What i need to do is execute a find with some filters AND price range query to fetch just the matching array elements and not all:
This is what i try:
var sort = {};
var query = {name:new RegExp("xx",'i')};
query['$and'] = [{'rooms.price':{$gt:50000}},{'rooms.price':{$lt:100000}}];
var page = 1;
var ppp = 20;
db.collection("myCollection").
find(query).
sort(sort).
skip(page > 0 ? ((page-1)*ppp) : 0).limit(ppp).toArray(function(err, docs) {
res.send(docs);
});
and i retrieve the same document.
What i need is :
{
"name" : "xxx",
"address" : " ",
"mail" : "",
"url" : "",
"pos" : {
"lat" : yyy,
"lng" : zzz
},
"rooms" : [
{
"_id" : ObjectId("540ce3f8e4b016292085b53d"),
"supplier" : "s3",
"price" : 53500,
"details" : [
{
"price" : 32100,
"key" : "2-1"
},
{
"price" : 21400,
"keykey" : "2-0"
}
]
}
]
}
I googled about but i find just aggregate or map/reduce element.
I'd like to avoid it.
Is there a good solution??
Thanks!
If you don't want to use aggregate or map/reduce then you could change your data structure.
Extract rooms to it's own collection and make sure that every element has id reference to the appropriate document from myCollection. This would require at least two query though.
Alternatively, you could filter the content on the application side and not within mongodb.

Resources