"open" suppose to take a boolean value and I should be able to do my filter the results with it but I'm ending up with an empty array as result, excuse the messy code please
let queryToMatch = [{$match: {name: project}},{$unwind:"$issues"}];
if(_id != undefined){
queryToMatch.push({$match: {"_id": _id}})
}
if(open != undefined){
queryToMatch.push({$match: {"open": open}})
}
if(issue_title != undefined){
queryToMatch.push({$match:{"issue_title": issue_title}})
}
if(issue_text != undefined){
queryToMatch.push({$match:{"issue_text": issue_text}})
}
if(created_by != undefined){
queryToMatch.push({$match:{"created_by": created_by}})
}
if(assigned_to != undefined){
queryToMatch.push({$match:{"assigned_to": assigned_to}})
}
if(status_text != undefined){
queryToMatch.push({$match:{"status_text": status_text}})
}
console.log(queryToMatch)
res.json("works")
Project.aggregate(queryToMatch, (err, data) => {
//console.log(data)
res.json(data)
})
You have not included the schema, or sample documents you are attempting to query. For this reason my answer may not be as you expect.
If I add the following documement...
db.test.insert(
{
"_id" : ObjectId("60b44ae6af90ae8f4deca589"),
"name": "project",
"open": "open",
"issue_title": "mytitle",
"issue_text": "mytext",
"created_by": "barry",
"assigned_to": "john",
"status_text": "mystatus",
"issues": [
{
"issue_type": "type1",
"issue_date": new Date
},
{
"issue_type": "type2",
"issue_date": new Date
},
{
"issue_type": "type3",
"issue_date": new Date
},
]
}
)
I can run the following mongo shell commands...
var _id = ObjectId("60b44ae6af90ae8f4deca589");
var open = "open";
var issue_title = "mytitle";
var issue_text = "mytext";
var created_by = "barry";
var assigned_to = "john";
var status_text = "mystatus";
let queryToMatch = [{"$match": {"name": "project"}},{$unwind:"$issues"}];
if(_id != undefined){
queryToMatch.push({$match: {"_id": _id}})
}
if(open != undefined){
queryToMatch.push({$match: {"open": open}})
}
if(issue_title != undefined){
queryToMatch.push({$match:{"issue_title": issue_title}})
}
if(issue_text != undefined){
queryToMatch.push({$match:{"issue_text": issue_text}})
}
if(created_by != undefined){
queryToMatch.push({$match:{"created_by": created_by}})
}
if(assigned_to != undefined){
queryToMatch.push({$match:{"assigned_to": assigned_to}})
}
if(status_text != undefined){
queryToMatch.push({$match:{"status_text": status_text}})
}
... then I can issue the following aggregate statement...
db.test.aggregate(queryToMatch).pretty()
... and I get the following results...
{
"_id" : ObjectId("60b44ae6af90ae8f4deca589"),
"name" : "project",
"open" : "open",
"issue_title" : "mytitle",
"issue_text" : "mytext",
"created_by" : "barry",
"assigned_to" : "john",
"status_text" : "mystatus",
"issues" : {
"issue_type" : "type1",
"issue_date" : ISODate("2021-05-31T02:46:04.670Z")
}
}
{
"_id" : ObjectId("60b44ae6af90ae8f4deca589"),
"name" : "project",
"open" : "open",
"issue_title" : "mytitle",
"issue_text" : "mytext",
"created_by" : "barry",
"assigned_to" : "john",
"status_text" : "mystatus",
"issues" : {
"issue_type" : "type2",
"issue_date" : ISODate("2021-05-31T02:46:04.670Z")
}
}
{
"_id" : ObjectId("60b44ae6af90ae8f4deca589"),
"name" : "project",
"open" : "open",
"issue_title" : "mytitle",
"issue_text" : "mytext",
"created_by" : "barry",
"assigned_to" : "john",
"status_text" : "mystatus",
"issues" : {
"issue_type" : "type3",
"issue_date" : ISODate("2021-05-31T02:46:04.670Z")
}
}
It seems your code does work in the context of mongo shell. My advice is to combine the $match stages together first, then perform the $unwind. I assume each of the predicates you are tacking on via a push are intended to be an 'AND' condition, not an 'OR' condition. Here is what the end result of your aggregation looks like after all the logical shenanigans...
[
{
"$match" : {
"name" : "project"
}
},
{
"$unwind" : "$issues"
},
{
"$match" : {
"_id" : ObjectId("60b44ae6af90ae8f4deca589")
}
},
{
"$match" : {
"open" : "open"
}
},
{
"$match" : {
"issue_title" : "mytitle"
}
},
{
"$match" : {
"issue_text" : "mytext"
}
},
{
"$match" : {
"created_by" : "barry"
}
},
{
"$match" : {
"assigned_to" : "john"
}
},
{
"$match" : {
"status_text" : "mystatus"
}
}
]
Perhaps this is a cleaner and easier to read query...
[
{
"$match" : {
"_id" : ObjectId("60b44ae6af90ae8f4deca589"),
"name" : "project",
"open" : "open",
"issue_title" : "mytitle",
"issue_text" : "mytext",
"created_by" : "barry",
"assigned_to" : "john",
"status_text" : "mystatus"
}
},
{
"$unwind" : "$issues"
},
]
Consider instead of using push you create an object for your $match predicate...
var match = new Object();
match.name = "project";
if(_id != undefined){
match._id = _id;
}
if(open != undefined){
match.open = open;
}
if(issue_title != undefined){
match.issue_title = issue_title;
}
if(issue_text != undefined){
match.issue_text = issue_text;
}
if(created_by != undefined){
match.created_by = created_by;
}
if(assigned_to != undefined){
match.assigned_to = assigned_to;
}
if(status_text != undefined){
match.status_text = status_text;
}
let queryToMatch = [{"$match": match},{$unwind:"$issues"}];
db.test.aggregate(queryToMatch).pretty()
Related
I am trying to update field value in mongoose.
{
"_id" : ObjectId("5b62c772efedb6bd3f0c983a"),
"projectID" : ObjectId("0000000050e62416d0d75837"),
"__v" : 0,
"clientID" : ObjectId("00000000996b902b7c3f5efa"),
"inspection_data" : [
{
"pdf" : null,
"published" : "N",
"submissionTime" : ISODate("2018-08-02T08:57:08.532Z"),
"userID" : ObjectId("00000000cac68e3bc04643f7"),
"insSummary" : "inspected areas",
"insName" : "Infotech",
"_id" : ObjectId("5b62c772fa02622a18655e7b"),
"published_date" : ISODate("2018-08-02T08:57:22.041Z"),
"locationAspects" : [
{
"aspectname" : "Ground floor",
"_id" : ObjectId("5b62c772fa02622a18655e80"),
"comments" : [
{
"_id" : ObjectId("5b62c772fa02622a18655e81"),
"images" : [
{
"path" : "/uploads/inspection/00000000996b902b7c3f5efa/images/1533200242005-IpjLKH4XFWNEcHXa.png",
"img_name" : "1533200242005-IpjLKH4XFWNEcHXa.png",
"title" : "Fan",
"id" : "1"
},
{
"path" : "/uploads/inspection/00000000996b902b7c3f5efa/images/1533200242008-YN8IlA5yrMn3cBnn.png",
"img_name" : "1533200242008-YN8IlA5yrMn3cBnn.png",
"title" : "Box",
"id" : "2"
}
],
"comment" : [
"comment4"
],
"recommendation" : ""
}
]
}]
}
Here I want to update a title Fan in image array as table fan.
I tried $set but I don't know how to do for my db structure.
Kindly give some solution to this
**Updated:**
I tried this code:
mongo.inspection.update({"projectID" : mongoose.Types.ObjectId(req.body.project_id) },
{ "$set": {
"inspection_data.$[e1].locationAspects.$[e2].comments.$[e3].images.$[e4].title" : "TableFan"
}},
{ "arrayFilters": [
{ "e1._id": mongoose.Types.ObjectId(req.body.insId)},
{ "e2._id": mongoose.Types.ObjectId(req.body.aspectId)},
{ "e3._id": mongoose.Types.ObjectId(req.body.commentId)},
{ "e4.id": "1" }
]},function(err,response){
if(err){
console.log("error")
}
else{
console.log('Updated')
console.log(response)
}
})
db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )
Its showing updated but in my db there is no change. Is any mistake I did ?
You can try with arrayFilters in mongodb
var mongoose = require('mongoose')
Temp.update(
{ "_id" : mongoose.Types.ObjectId("5b62c772efedb6bd3f0c983a") },
{ "$set": {
"inspection_data.$[e1].locationAspects.$[e2].comments.$[e3].images.$[e4].title": "TableFan"
}},
{ "arrayFilters": [
{ "e1._id": mongoose.Types.ObjectId("5b62c772fa02622a18655e7b") },
{ "e2._id": mongoose.Types.ObjectId("5b62c772fa02622a18655e80") },
{ "e3._id": mongoose.Types.ObjectId("5b62c772fa02622a18655e81") },
{ "e4.id": "1" }
]}
)
Note: You have to cast _id to ObjectId
I have a JSON object in my MONGODB
{
"_id" : ObjectId("59d4b9848621854d8fb2b1e1"),
"Bot_name" : "Scheduling bot",
"Modules" : [
{
"ModuleID" : "1111",
"ModuleStatement" : "This is a Sceduling bot, Would you like to book a flight?",
"_id" : ObjectId("59d4b9968621854d8fb2b1e3"),
"ModuleResponse" : [
{
"Response" : "yes",
"TransBotID" : "1112"
},
{
"Response" : "no",
"TransBotID" : "1113"
}
]
},
{
"ModuleID" : "1112",
"ModuleStatement" : "Where would you like to go? New York ? LA?",
"_id" : ObjectId("59d4b9968621854d8fb2b1e3"),
"ModuleResponse" : [
{
"Response" : "New York",
"TransBotID" : "1121"
},
{
"Response" : "LA",
"TransBotID" : "1122"
}
]
},
{
"ModuleID" : "1121",
"ModuleStatement" : " New York..",
"_id" : ObjectId("59d4b9968621854d8fb2b1e3"),
"ModuleResponse" : []
},
{
"ModuleID" : "1121",
"ModuleStatement" : " New York..",
"_id" : ObjectId("59d4b9968621854d8fb2b1e3"),
"ModuleResponse" : []
}
}
Im making a query that will first check the Bot_name and then check the ModuleID which is in the nested array Modules containing JSON object which are 1111, 1112 , 1121 .. so on
how do i only get the json object of ModuleID:1111 of Bot_name:Scheduling bot
so far my query is
botSchema.findOne({ Bot_name: req.body.Name ,'Modules.ModuleID':req.body.MID}, function (err, data) {
console.log(data)
}
here the query returns all the json inside the Modules
how to only get one desired json object? like this
{
"ModuleID" : "1111",
"ModuleStatement" : "This is a Sceduling bot, Would you like to book a flight?",
"_id" : ObjectId("59d4b9968621854d8fb2b1e3"),
"ModuleResponse" : [
{
"Response" : "yes",
"TransBotID" : "1112"
},
{
"Response" : "no",
"TransBotID" : "1113"
}
]
}
You need to use $elemMatch for filter sub arrays.
db.botSchema.findOne(
{ Bot_name: "Scheduling bot"}
, { 'Modules': { $elemMatch:{'ModuleID':"1111"} } }
, function (err, data) { console.log(data) })
Result:
{
"_id" : ObjectId("59d4b9848621854d8fb2b1e1"),
"Modules" : [
{
"ModuleID" : "1111",
"ModuleStatement" : "This is a Sceduling bot, Would you like to book a flight?",
"_id" : ObjectId("59d4b9968621854d8fb2b1e3"),
"ModuleResponse" : [
{
"Response" : "yes",
"TransBotID" : "1112"
},
{
"Response" : "no",
"TransBotID" : "1113"
}
]
}
]
}
I'm trying to find objects using the built it queries and It just doesn't work..
My JSON file is something like this:
{ "Text1":
{
"id":"2"
},
"Text2":
{
"id":"2,3"
},
"Text3":
{
"id":"1"
}
}
And I write this db.myCollection.find({"id":2})
And it doesn't find anything.
When I write db.myCollection.find() it shows all the data as it should.
Anyone knows how to do it correctly?
Its hard to change the data-structure but as you want just your matching sub-document and you don't know where is your target sub-document (for example the query should be on Text1 or Text2 , ...) there is a good data structure for this:
{
"_id" : ObjectId("548dd9261a01c68fab8d67d7"),
"pair" : [
{
"id" : "2",
"key" : "Text1"
},
{
"id" : [
"2",
"3"
],
"key" : "Text2"
},
{
"id" : "1",
"key" : "Text3"
}
]
}
and your query is:
db.myCollection.findOne({'pair.id' : "2"} , {'pair.$':1, _id : -1}).pair // there is better ways (such as aggregation instead of above query)
as result you will have:
{
"0" : {
"id" : "2",
"key" : "Text1"
}
}
Update 1 (newbie way)
If you want all the document not just one use this
var result = [];
db.myCollection.find({'pair.id' : "2"} , {'pair.$':1, _id : -1}).forEach(function(item)
{
result.push(item.pair);
});
// the output will be in result
Update 2
Use this query to get all sub-documents
db.myCollection.aggregate
(
{ $unwind: '$pair' },
{ $match : {'pair.id' : "2"} }
).result
it produce output as
{
"0" : {
"_id" : ObjectId("548deb511a01c68fab8d67db"),
"pair" : {
"id" : "2",
"key" : "Text1"
}
},
"1" : {
"_id" : ObjectId("548deb511a01c68fab8d67db"),
"pair" : {
"id" : [
"2",
"3"
],
"key" : "Text2"
}
}
}
Since your are query specify a field in a subdocument this is what will work. see .find() documentation.
db.myCollection.find({"Text1.id" : "2"}, {"Text1.id": true})
{ "_id" : ObjectId("548dd798e2fa652e675af11d"), "Text1" : { "id" : "2" } }
If the query is on "Text1" or "Text2" the best thing to do here as mention in the accepted answer is changing you document structure. This can be easily done using the "Bulk" API.
var bulk = db.mycollection.initializeOrderedBulkOp(),
count = 0;
db.mycollection.find().forEach(function(doc) {
var pair = [];
for(var key in doc) {
if(key !== "_id") {
var id = doc[key]["id"].split(/[, ]/);
pair.push({"key": key, "id": id});
}
}
bulk.find({"_id": doc._id}).replaceOne({ "pair": pair });
count++; if (count % 300 == 0){
// Execute per 300 operations and re-Init
bulk.execute();
bulk = db.mycollection.initializeOrderedBulkOp();
}
})
// Clean up queues
if (count % 300 != 0 )
bulk.execute();
Your document now look like this:
{
"_id" : ObjectId("55edddc6602d0b4fd53a48d8"),
"pair" : [
{
"key" : "Text1",
"id" : [
"2"
]
},
{
"key" : "Text2",
"id" : [
"2",
"3"
]
},
{
"key" : "Text3",
"id" : [
"1"
]
}
]
}
Running the following query:
db.mycollection.aggregate([
{ "$project": {
"pair": {
"$setDifference": [
{ "$map": {
"input": "$pair",
"as": "pr",
"in": {
"$cond": [
{ "$setIsSubset": [ ["2"], "$$pr.id" ]},
"$$pr",
false
]
}
}},
[false]
]
}
}}
])
returns:
{
"_id" : ObjectId("55edddc6602d0b4fd53a48d8"),
"pair" : [
{
"key" : "Text1",
"id" : [
"2"
]
},
{
"key" : "Text2",
"id" : [
"2",
"3"
]
}
]
}
Is there a way to get random values from a JSON file? My JSON contains a lot of content based on same musical artist, so I wanted to display data more randomly and add a show more button afterwards...
so my JSON looks something like this:
[
data: [{
"name" : "rihanna",
"song" : "pour it up"
},
{
"name" : "rihanna"
"song" : "diamonds"
},
{
"name" : "ladygaga"
"song" : "lovegame"
},
{
"name" : "ladygaga"
"song" : "lovegame"
},
{
"name" : "ladygaga"
"song" : "pokerface"
},
{
"name" : "ladygaga"
"song" : "alejandro"
},
{
"name" : "fergie"
"song" : "fergalicious"
},
{
"name" : "fergie"
"song" : "clumsy"
},
etc etc
So, is there a way to achieve this?
Try this :)
var random = Math.floor(Math.random() * jsonObject.length);
var rData = jsonObject[random];
P.S. : Where jsonObject ist your data property.
Here is how you can acheive it. PLUNKER
$(document).ready(function() {
$('button').on('click', function() {
getRandom();
var html = template(context);
$('#artistlist').html(html);
});
var source = $("#entry-template").html();
var template = Handlebars.compile(source);
var musicArray = [{
"name": "rihanna",
"song": "pour it up"
}, {
"name": "rihanna",
"song": "diamonds"
}, {
"name": "ladygaga",
"song": "lovegame"
}, {
"name": "ladygaga",
"song": "lovegame"
}, {
"name": "ladygaga",
"song": "pokerface"
}, {
"name": "ladygaga",
"song": "alejandro"
}, {
"name": "fergie",
"song": "fergalicious"
}, {
"name": "fergie",
"song": "clumsy"
}];
var context = {
music: []
};
var musicClone = $.extend(true, [], musicArray);
function getRandom() {
var i = 2;
while (i-- && musicClone.length >= 1) {
var random = Math.floor(Math.random() * musicClone.length);
var data = musicClone[random];
context.music.push(data);
musicClone.splice(random, 1);
}
}
});
Given this json structure:
{
"categoryID" : 1,
"categoryName" : "Stupid Questions",
"questions" : [{
"question" : [{
"questionOptions" : [{
"questionOptionID" : 1,
"optionText" : "It's top secret."
}, {
"questionOptionID" : 2,
"optionText" : "Because I am big and your small. I am right and your wrong."
}, {
"questionOptionID" : 3,
"optionText" : "I will gladly pay you Tuesday for a hamburger today."
},
],
"questionType" : "checkbox",
"questionText" : "Why can't we use more abstract table and column names?",
"summary" : "Question of the year"
}
]
}
]
}
I would like to map both the questions and questionOptions to template and templateOptions:
{
"categoryID" : 1,
"categoryName" : "Stupid Questions",
"templates" : [{
"template" : [{
"templateOptions" : [{
"templateOptionID" : 1,
"optionText" : "It is top secret."
}, {
"QuestionOptionID" : 2,
"OptionText" : "Because we are lazy."
}, {
"QuestionOptionID" : 3,
"OptionText" : "I will gladly pay you Tuesday for a hamburger today."
},
],
"QuestionType" : "checkbox",
"QuestionText" : "Why can't we use more abstract table and column names?",
"Summary" : "Question of the year"
}
]
}
]
}
Here is the start to my knockout mapping object:
var templateMapping = {
'templates': {
templates: function(data) {
return ko.utils.unwrapObservable(data.questions);
}
}
//how do I map observable array of question options to observable array of template options here?
};
The key in this mapping is that the sub objects have a different structure (unlike this question - https://stackoverflow.com/a/7535397/466321). It seems like all of the mapping examples I have found don't cover how this may get done, and I have unsuccessfully tried a couple of theories of my own.
#Jeff Mercado is right. The mapper is not intended for this. To accomplish what you intend, it takes a bit of recursive javascript.
function myTransform(string) {
// case-insensitive replace
return string.replace(/question/i,'template');
}
function transformObject(source) {
var result = {}
for( var key in source ) {
if( !source.hasOwnProperty(key) ) continue;
var value = source[key];
var newKey = myTransform(key);
if( Object.prototype.toString.call(value) == "[object Array]" ) {
result[newKey] = [];
for( var i in value ) {
if( !value.hasOwnProperty(i) ) continue;
result[newKey][i] = transformObject(value[i]);
}
}
else if( Object.prototype.toString.call(value) == "[object Object]" ) {
result[newKey] = transformObject(value);
}
else {
result[newKey] = value;
}
}
return result;
}
var wow = transformObject(json);
See this fiddle