Select subdocument where - javascript

This is probably a noobish question, however I have spent quite some time on it now.
So this is my structure, highly minimized:
{
name : 'Some dude',
deck : [{
name : 'Awesome card',
value : 30
},
{
name : 'another awesome card',
value: 50
}]
}
I want to select from all cards in the deck, where name == 'Awesome card', returning this
{
name : 'Some dude',
deck : [{
name : 'Awesome card',
value : 30
}]
}
been trying loads of commands like
db.heroes.find({name : "Some dude"}, {'deck' : 1, 'deck.name' : 'Awesome card})
How should I query this?

Use $elemMatch projection:
db.heroes.find({name : "Some dude"}, {'deck' : {$elemMatch:{name:'Awesome card}}})
See docs here.

You can use the $ position operator which identifies the index of the matched deck array element in your field selection:
db.heroes.find(
{name : "Some dude", 'deck.name' : 'Awesome card'},
{_id: 0, name: 1, 'deck.$.name': 1}
);

deck = deck.filter(function (card) { return card.name === 'Awesome card' });
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter

Related

Mongoose : get content of multiple subdocument in one object

Hello I've been trying to select all the subdocument of multiple document returned in ONE single object and if it's possible sorted by value.
Here is what I mean :
My collection :
{
userId: 1,
...
items : [
{name: "candle", value:5},
{name: "shoes", value: 200}
]
},
{
userId: 2,
...
items : [
{name: "burger", value:17},
{name: "car", value: 5000}
]
},
{
userId: 3,
...
items : [
{name: "chips", value:2},
]
}
And I want to make a query that return me something like that :
[
{userId:1, name: "candle", value:5},
{userId:1, name: "shoes", value: 200},
{userId:2, name: "burger", value:17},
{userId:2, name: "car", value: 5000},
{userId:3, name: "chips", value:2}
]
I've been trying this :
Mymodel.find({}).select("items"); //It return me all the items but in separate object. [ {items: []} ...]
Also if it is possible I would like to sort them : I want to get the 3 most valuable items in the users collection. I tried to use the aggregate method following some example in the mongoose doc but I didn't succeed to make it work. I also have been thinking to make a new database containing only the users items so I can sort them easily but I feel like there is a better solution to do this.
So my question is do you have an idea how could I make it work ? thank you in advance
I'm pasting just an option
var pipeline = [
{
"$unwind" : "$items"
},
{
"$addFields" : {
"name" : "$items.name",
"value" : "$items.value"
}
},
{
"$unset" : "items"
},
{
"$project" : {
"_id" : 0,
"name" : 1,
"value" : 1,
"userId" : 1
}
}
]
Run db.collname.aggregate(pipeline) or review the syntax for the driver.

Mongoose query returning more than one result

My database structure is looking like this :
{
'name' : 'entry one'
'project' :
[
{companyName : 'a name', contactPerson : [{ work_email: 'test#test.com'}] } ,
{companyName : 'a name1', contactPerson : [{ work_email: 'test1#test.com'}] } ,
{companyName : 'a name2', contactPerson : [{ work_email: 'test2#test.com'}] }
]
}
{
'name' : 'entry 2'
'project' :
[
{companyName : 'another name', contactPerson : [{ work_email: 'testing#test.com'}] } ,
{companyName : 'another name1', contactPerson : [{ work_email: 'testing1#test.com'}] } ,
{companyName : 'another name 2', contactPerson : [{ work_email: 'testing2#test.com'}] }
]
}
What i want is to find the companyName that belongs to a given work_email. So if the work_email is test#test.com the company name that should be returned should be 'a name'
So the query i built with mongoose is this :
const projects = await ClientManagers.findOne({'project.contactPerson.work_email' : 'test#test.nl'} , 'project.companyName');
But this is returning all company names (from entry one) not the single one i am looking for.
Filtering will always return whole document. You need to use projection to "reshape" it. You can consider the $ (projection) operator:
const projects = await ClientManagers.findOne({'project.contactPerson.work_email' : 'test#test.nl'} , { 'project.$': 1 });
Mongo Playground

Exact match in datagrid-filter

I've been having problem trying to implement exact match searching in a column inside a table using datagrid-filter.
For example:
Under column Name if I search "Name 1" the search result would only display only Name 1.
Can anyone teach me how to do it?
I'd really appreciate your help.
$(function(){
var rows = [];
for(var i=1; i<=800; i++){
var amount = Math.floor(Math.random()*1000);
var price = Math.floor(Math.random()*1000);
rows.push({
inv: 'Inv No '+i,
date: $.fn.datebox.defaults.formatter(new Date()),
name: 'Name '+i,
amount: amount,
price: price,
cost: amount*price,
note: 'Note '+i
});
}
$('#tt').datagrid({
view : scrollview,
striped : true,
pagination : false,
pageSize : 50,
singleSelect : false,
autoRowHeight: false,
remoteFilter : false,
remoteSort : true,
multiSort : true,
});
$('#tt').datagrid('enableFilter', [{
field:'amount',
type:'numberbox',
options:{
precision:0
},
op:['equal','notequal','less','greater']
}])
$('#tt').datagrid('loadData', rows);
});
Please refer to this jsfiddle:
http://jsfiddle.net/6u2b8pyp/
Add following at the beginning on document ready to avoid case sensitive behavior
$.fn.datagrid.defaults.operators =
{
equal: {
text: 'Equal',
isMatch: function(source, value){
return source.toLowerCase() == value.toLowerCase();
}
}
};
Replacing
$('#tt').datagrid('enableFilter', [{
field:'amount',
type:'numberbox',
options:{
precision:0
},
op:['equal','notequal','less','greater']
}])
to
$('#tt').datagrid('enableFilter', [{
field:'amount',
type:'numberbox',
options:{
precision:0
},
op:['equal','notequal','less','greater']
},{
field:'name',
type:'textbox',
options:{
precision:0
},
defaultFilterOperator: 'equal'
}])
will do Your fiddle mod
According to the docs, you can specify a default operator for your filters, like this:
$('#tt').datagrid({
(...)
defaultFilterOperator: 'equal'
});
This uses exact, case-sentitive matches, which may or may not be what you want ("name 1" will not work if the name is "Name 1"). I did not see a case-insensitive option.

Apply an expression to each array element in document

I've got a sample document that I'm trying to project within a MongoDB aggregate pipeline. I'm testing with a single document that looks roughly like this:
{
"_id" : "",
"title" : "Questions",
"sortIndex" : 0,
"topics" : [
{
"_id" : "",
"title" : "Creating a Question",
"sortIndex" : 1,
"thumbnail" : "CreatingAQuestion.jpg",
"seenBy" : [ "user101", "user202" ],
"pages" : [
{
"visual" : "SelectPlanets.gif",
"text" : "Some Markdown"
}
]
},
{
"_id" : "",
"title" : "Deleting a Question",
"sortIndex" : 0,
"thumbnail" : "DeletingAQuestion.jpg",
"seenBy" : [ "user101" ],
"pages" : [
{
"visual" : "SelectCard.gif",
"text" : "Some Markdown"
}
]
}
]
}
The output I'm trying to obtain is something along these lines:
{
"_id" : "",
"title" : "Questions",
"topics" : [
{
"title" : "Creating a Question",
"thumbnail" : "CreatingAQuestion.jpg",
"seen" : true
},
{
"title" : "Deleting a Question",
"thumbnail" : "DeletingAQuestion.jpg",
"seen" : false
}
]
}
Specifically the bit I'm struggling with is the seen flag.
I've read the docs which state:
When projecting or adding/resetting a field within an embedded document...
... Or you can nest the fields:
contact: { address: { country: <1 or 0 or expression> } }
I wish to use an expression and I took note of the following:
When nesting the fields, you cannot use dot notation inside the embedded document to specify the field, e.g. contact: { "address.country": <1 or 0 or expression> } is invalid.
So I'm trying to work out how to "reference" a subdocument field within an expression. That quote suggests I can't use dot notation but when I can't seem to get it working with nested notation either. Here's what I've got so far:
db
.getCollection('chapters')
.aggregate([
{
$project: {
title: 1,
topics: {
title: 1,
thumbnail: 1,
publishedAt: 1,
test: "$seenBy",
seen: { $in: ["user202", "$seenBy"] },
}
}
}
])
So I've hard coded user202 into my query for now, and expected to see true and false for the 2 documents. I've also put in a test field to map out the seenBy field from the sub-document. What this produces is:
{
"_id" : "",
"title" : "Questions",
"topics" : [
{
"title" : "Creating a Question",
"thumbnail" : "CreatingAQuestion.jpg",
"test" : [
"user101",
"user202"
],
"seen" : true
},
{
"title" : "Deleting a Question",
"thumbnail" : "DeletingAQuestion.jpg",
"test" : [
"user101",
"user202"
],
"seen" : true
}
]
}
So obviously my "$seenBy" isn't accessing the correct topic because the test field contains the data from the 1st document.
So ultimately my question is, how can I access the seenBy field within a subdocument, referring to the current subdocument so I can create an expression?
Note: I have got this working with multiple $project and an $unwind but wanted to try compress/clean it up a bit.
You really need to use $map here. Simply notating the array in projection ( which is a bit of a boon since MongoDB 3.2 ) does not really cut it when you need a localized value for the current element. That is what you need and it's what $map provides:
db.getCollection('chapters').aggregate([
{ $project: {
title: 1,
topics: {
$map: {
input: "$topics",
as: "t",
in: {
title: "$$t.title",
thumbnail: "$$t.thumbnail",
publishedAt: "$$t.publishedAt",
test: "$$t.seenBy",
seen: { $in: ["user202", "$$t.seenBy"] },
}
}
}}
])
So for each element the current value of "seenBy" as a property is being tested by the expression. Without the $map that is not possible, and you can only really notate the "whole" array. Which is really not what you want to test here.

Finding a particular object in an array mongoDB

I have a collection that is composed of some strings, objects, and one array. Within that array are several objects. I am attempting to remove all of the orders with the object id of ObjectId("587ec66e5ed5cb0061092dbe"). See below for the schema and related data. I have tried everything under the sun.
var campgroundSchema = new mongoose.Schema({
name: String,
image: String,
description: String,
price: String,
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
},
orders: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Order"
}
]
});
Below is sample data.
{
"_id" : ObjectId("587ec65e5ed5cb0061092dbd"),
"name" : "is Forrest Cool?",
"price" : "",
"image" : "https://dsafd.com",
"description" : "",
"orders" :
[
ObjectId("587ec66e5ed5cb0061092dbe"),
ObjectId("587ec6bc5ed5cb0061092dc0"),
ObjectId("587ec6c05ed5cb0061092dc2"),
ObjectId("587ec7178f628931610636dc"),
ObjectId("587ec71e8f628931610636de")
],
"author" : { "id" : ObjectId("587ec6145ed5cb0061092dbc"),
"username" : "forrest" },
"__v" : 18
}
Thank you so much.
To find the specific element with particular ObjectId inside orders array, You can use $in.
Try this:
//orderObjectId is the object id you want to find inside orders.
Campground.find({orders : {$in : [orderObjectId]}},{'orders.$':1},function(err,result){
...
});
'orders.$':1 will return only that element from orders array
To delete that particular order,
//_id is optional, you can query using orderID also.
Campground.update({
_id :someObjectId, orders : {$in : [orderObjectId]}
},{
$pull : {order : orderObjectId}
},function(err,result){
...
});
Update:
Accroding to your comment, it seems you are having facing problem using this.
Try this:
//if you are receiving orderId as string, convert string to ObjectId
var orderId = mongoose.Schema.Types.ObjectId("587d78b8e898d1e732b3888a");
Campground.find({"orders": {$in : [orderId]}},function(err, result){
if(err){
console.log(err);
} else {
console.log("FOUND RESULT: " + result);
}
});
Hope this helps.

Categories