mongodb pull element from array - mongodb

I have the following schema:
{
"_id" : 27,
"n" : [{
"d" : new Date("Sat, 24 Dec 2011 17:03:00 GMT +04:00"),
"e" : ObjectId("4f0aef5346b3b88013000001"),
"f" : [26, 10, 16],
"k" : new Date("Mon, 09 Jan 2011 17:44:51 GMT +04:00"),
"t" : "f",
"u" : 10
}, {
"a" : ObjectId("4f0c208846b3b8140f000000"),
"d" : new Date("Tue, 10 Jan 2012 15:27:21 GMT +04:00"),
"p" : [ObjectId("4f0c209046b3b8340f000000"), ObjectId("4f0c209346b3b8340f000001"), ObjectId("4f0c209646b3b8340f000002"), ObjectId("4f0c209946b3b8340f000003")],
"t" : "p",
"u" : 10
}]
}
and this query removes all of the sub elements if at least one satisfy it
db.newsFeed.update({ "_id" : 27, },{
$pull : {
'n' : {
'd' : {
$lte : new Date(2012, 1, 1)
}
}
}
});
so the document becomes like this,
{
"_id" : 27,
"n" : []
}
what am I doing wrong, and more important what should I do to pull just some of the elements?

I think your query is fine, the problem is the date you're using.
Instead of:
new Date(2012, 1, 1)
Try:
ISODate("2012-01-01")
Try typing them in the shell by themselves and you'll get back these results:
> new Date(2012, 1, 1)
ISODate("2012-02-01T07:00:00Z")
> ISODate("2012-01-01")
ISODate("2012-01-01T00:00:00Z")
At least, that's what I see in my shell. Using the "new" returns a date that matches on both elements of your array, so they're both removed. Using ISODate directly creates the date object you're looking for and only matches on the first result.
The Date constructor takes a zero based month, so you want this if you want to use new:
new Date(2012, 0, 1)

Related

Mongo db query for getting records of and delete 2018

I am using below query to find records for 2018. my query is to find first 2018 records and then delete
2018 records. can i delete from GUI Robo3t?
db.transaction.find().sort({timeStamp:1}).limit(5000);
sample document:
{
"_id" : 999999001,
"eventId" : "LAS071",
"eventName" : "YouRefer",
"timeStamp" : "2018-06-17T17:12:55.254Z",
"eventMethod" : "Reporting",
"resourceName" : "AddSTB",
"targetType" : "",
"resourseUrl" : "",
"operationName" : "",
"functionStatus" : "",
"pageId" : "CloseJobView",
"ban" : 144235039,
"jobId" : 139980225,
"wrid" : 139980225,
"jobType" : "MRJ2IX",
"Uid" : "kt7201",
"techRegion" : "SE",
"mgmtReportingFunction" : "N",
"recordPublishIndicator" : "Y"
}
I used the query and getting in finding records:
db.transaction.deleteMany({
"timeStamp": { $gte: new Date(2018, 0, 1), $lt: new Date(2019, 0, 1) }
})
but i have around 100k records of 2018. How can we use above query for deletion of 5K records at a time?
I tried with finding first in collection, but it's saying 0 records fetched.
db.transaction.find({
"timeStamp": { $gte: new Date(2018, 0, 1), $lt: new Date(2019, 0, 1) }
})
Output: Fetched 0 record(s) in 31ms
But i checked in collection below records with these timestamp are present,
"timeStamp" : ISODate("2018-12-31T18:30:03.379Z"),
"timeStamp" : ISODate("2018-12-31T18:30:03.982Z"),
This a shell command to delete all documents from the year 2018:
db.transaction.deleteMany({
"timeStamp": { $gte: new Date(2018, 0, 1), $lt: new Date(2019, 0, 1) }
})
It works by querying for all records with a timeStamp greater than or equal to January 1st 2018, and with a timeStamp less than January 1st 2019.
Edit
Your timeStamp field seems to be a string. Try using this query that looks for the string 2018:
{ "timeStamp": { $regex: "^2018" } }

How can I remove older records from a collection in MongoDB?

How can I remove older documents from a collection, older than seven days?
{ "orderID" : "456986", "orderType" : "OnlinePurchase", "orderStatus" : "expired", "address" : "Hexel", "payement" : "Card", "isDomestic" : true, "orderExpDate" : ISODate("2017-09-20T20:36:11.000Z"), "shipped" : false }
For removing documents before Date, your command should be:
db.collection.deleteMany( { orderExpDate : {"$lt" : new Date(YEAR, MONTH, DATE) } })
For removing records before 1 October 2017, the command will be:
db.collection.deleteMany( { orderExpDate : {"$lt" : new Date(2017, 9, 1) } })
October is the 10th month. If the month field is zero indexed, then we use 9, otherwise use 10.
...........................
This will remove all records older than seven days:
db.collection.deleteMany( { orderExpDate : {"$lt" : new Date(Date.now() - 7*24*60*60 * 1000) } })
Update: collection.remove is deprecated
db.collection.remove has been deprecated. You should use:
db.collection.deleteMany( { orderExpDate : {"$lt" : new Date(2017, 9, 1) } }))

Filter (nested) boolean field in Mongo / Meteor

I have a Mongo collection (using Meteor) structured like so:
{
"_id" : "xx",
"name" : "xx",
"handle" : "xx",
"tweets" : [
{
"published" : true,
"tweet_id" : "xx",
"text" : "xx",
"created_at" : "Mon Jul 31 18:18:38 +0000 2017",
"retweet_count" : 0,
"from" : "x",
"from_full_name" : "x",
"from_profile_image" : "x"
},
{
"published" : true,
"tweet_id" : "xx",
"text" : "xx",
"created_at" : "Mon Jul 31 18:18:38 +0000 2017",
"retweet_count" : 0,
"from" : "x",
"from_full_name" : "x",
"from_profile_image" : "x"
},
{
"published" : false,
"tweet_id" : "xx",
"text" : "xx",
"created_at" : "Mon Jul 31 18:18:38 +0000 2017",
"retweet_count" : 0,
"from" : "x",
"from_full_name" : "x",
"from_profile_image" : "x"
},
]
}
I only want to display the published tweets. I am using a template helper to retrieve and filter:
return Tweets.find({
handle:handle,
"tweets.published": true
});
I cannot seem to get the nested filter on 'published' to work. All tweets are displayed, using the above code. I have tried many different permutations of the "tweets.published": true. What is the correct way to filter out the unpublished tweets?
Since the tweets field is an array of objects, not just one object, your method will not work.
First you should use the handle to find the correct document:
return Tweets.find({
handle: handle,
});
This must then be combined with a fields, to select tweets which should be returned.
return Tweets.find({
handle: handle,
}, {
fields: { tweets: { $elemMatch: { published: true } } }
});
the $elemMatch part specifies the tweet must be publised. More information on the mongo page.
EDIT
If the snippet must run on the client (in your case), you have other options. You can use a server publication with my snippet to only give published tweets to the client.
Alternatively, give the transform option to the find request.
return Tweets.find({
handle: handle
}, {
transform: doc => {
doc.tweets = doc.tweets.filter(tweet => tweet.published);
return doc;
}
});

mongo query select only first of month

is it possible to query only the first (or last or any single?) day of the month of a mongo date field.
i use the $date aggregation operators regularly but within a $group clause.
basically i have field that is already aggregated (averaged) for each day of the month. i want to select only one of these days (with the value as a representative of the entire month.)
following is a sample of a record set from jan 1, 2014 to feb 1, 2015 with price as the daily price and 28day_avg as the trailing monthly average for 28 days.
{ "date" : ISODate("2014-01-01T00:00:00Z"), "_id" : ObjectId("533b3697574e2fd08f431cff"), "price": 59.23, "28day_avg": 54.21}
{ "date" : ISODate("2014-01-02T00:00:00Z"), "_id" : ObjectId("533b3697574e2fd08f431cff"), "price": 58.75, "28day_avg": 54.15}
...
{ "date" : ISODate("2015-02-01T00:00:00Z"), "_id" : ObjectId("533b3697574e2fd08f431cff"), "price": 123.50, "28day_avg": 122.25}
method 1.
im currently running an aggregation using $month data (and summing the price) but one issue is im seeking to retrieve the underlying date value ISODate("2015-02-01T00:00:00Z") versus the 0,1,2 value that comes with several of the date aggregations (that loop at the first of the week, month, year). mod(28) on a date?
method 2
i'd like to simply pluck out a single record of the 28day_avg as representative of the period. the 1st of the month would be adequate
the desired output is...
_id: ISODate("2015-02-01T00:00:00Z"), value: 122.25,
_id: ISODate("2015-01-01T00:00:00Z"), value: 120.78,
_id: ISODate("2014-12-01T00:00:00Z"), value: 118.71,
...
_id: ISODate("2014-01-01T00:00:00Z"), value: 53.21,
of course, the value will vary from method 1 to method 2 but that is fine. one is 28 days trailing while the other will account for 28, 30, 31 day months...dont care about that so much.
A non-agg is ok but also doesnt work. aka {"date": { "$mod": [ 28, 0 ]} }
To pick the first of the month for each month (method 2), use the following aggregation:
db.test.aggregate([
{ "$project" : { "_id" : "$date", "day" : { "$dayOfMonth" : "$date" }, "28day_avg" : 1 } },
{ "$match" : { "day" : 1 } }
])
You can't use an index for the match, so this is not efficient. I'd suggest adding another field to each document that holds the $dayOfMonth value, so you can index it and do a simple find:
{
"date" : ISODate("2014-01-01T00:00:00Z"),
"price" : 59.23,
"28day_avg" : 54.21,
"dayOfMonth" : 1
}
db.test.ensureIndex({ "dayOfMonth" : 1 })
db.test.find({ "dayOfMonth" : 1 }, { "_id" : 0, "date" : 1, "28day_avg" : 1 })

mongodb pull all element from the array

Suppose I have the following schema:
"_id" : 1,
"n" : [{
"a" : ObjectId("4ef0ca414653b7c866040000"),
"d" : new Date("Thu, 22 Dec 2011 04:53:56 GMT +04:00")
}, {
"a" : ObjectId("4ef0ca414653b9c866040000"),
"d" : new Date("Thu, 22 Dec 2011 04:54:11 GMT +04:00")
}, {
"a" : ObjectId("4ef0ca424653b9c866040000"),
"d" : new Date("Thu, 22 Dec 2011 04:54:30 GMT +04:00"),
}]
and I need to remove all n, where d is less than specific date.
So I thought I will be able to do this in the following way:
db.coll.update({
'_id': 1
},{
$pullAll : {
n.d : {
$lte : new Date(2000, 10, 11)
}
}
})
but the problem is, that it is not working this way.
Any suggestions?
That is not how $pullAll works. You cannot specify a matching condition, you can only specify an array of objects to be deleted (that need to match exactly).
Fortunately, you can use $pull instead (which does accept a matching condition):
db.coll.update({
'_id': 1
},{
$pull : {
n.d : {
$lte : new Date(2000, 10, 11)
}
}
})
Note that $pull also pulls all elements that match, not just one.
This is admittedly a little confusing.