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
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.
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
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.
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.
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.